diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2013-03-14 11:08:21 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2013-03-14 11:08:21 +0000 |
commit | 98260b7afb3fd0b4d628a36a1aa46eaebe4b72ca (patch) | |
tree | 3acca6237e111faf7672747c2ba30e4c91bc1228 /usr.sbin | |
parent | 924cf907d1385e13d36db11a3b3f5880fd8aa673 (diff) |
tedu faithd(8), suggested by todd@ some weeks ago after a submission by
dhill.
ok krw@, mikeb@, tedu@ (implicit)
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/faithd/Makefile | 13 | ||||
-rw-r--r-- | usr.sbin/faithd/README | 148 | ||||
-rw-r--r-- | usr.sbin/faithd/faithd.8 | 330 | ||||
-rw-r--r-- | usr.sbin/faithd/faithd.c | 885 | ||||
-rw-r--r-- | usr.sbin/faithd/faithd.h | 67 | ||||
-rw-r--r-- | usr.sbin/faithd/ftp.c | 953 | ||||
-rw-r--r-- | usr.sbin/faithd/prefix.c | 349 | ||||
-rw-r--r-- | usr.sbin/faithd/prefix.h | 52 | ||||
-rw-r--r-- | usr.sbin/faithd/tcp.c | 327 |
10 files changed, 2 insertions, 3126 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index d56781f62ce..147fd4d7c80 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -1,10 +1,10 @@ -# $OpenBSD: Makefile,v 1.165 2012/11/21 12:21:10 kettenis Exp $ +# $OpenBSD: Makefile,v 1.166 2013/03/14 11:08:20 mpi Exp $ .include <bsd.own.mk> SUBDIR= ac accton acpidump adduser amd apm apmd arp \ authpf bgpctl bgpd bind chroot config cron crunchgen dev_mkdb \ - dhcpd dhcrelay dvmrpctl dvmrpd edquota eeprom faithd fdformat \ + dhcpd dhcrelay dvmrpctl dvmrpd edquota eeprom fdformat \ ftp-proxy fw_update gpioctl hostapd hotplugd httpd ifstated ikectl \ inetd iostat iscsictl iscsid kgmon kvm_mkdb \ ldapd ldapctl ldomctl ldomd ldpd ldpctl lpr mailwrapper map-mbone \ diff --git a/usr.sbin/faithd/Makefile b/usr.sbin/faithd/Makefile deleted file mode 100644 index 139044900fe..00000000000 --- a/usr.sbin/faithd/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# $OpenBSD: Makefile,v 1.5 2002/09/08 01:23:22 deraadt Exp $ - -PROG= faithd -SRCS= faithd.c tcp.c ftp.c prefix.c - -MAN= faithd.8 - -#CPPFLAGS+= -DFAITH4 - -LDADD+= -lutil -DPADD+= ${LIBUTIL} - -.include <bsd.prog.mk> diff --git a/usr.sbin/faithd/README b/usr.sbin/faithd/README deleted file mode 100644 index 3e4e9e94f02..00000000000 --- a/usr.sbin/faithd/README +++ /dev/null @@ -1,148 +0,0 @@ -Configuring FAITH IPv6-to-IPv4 TCP relay - -Kazu Yamamoto and Jun-ichiro itojun Hagino -$OpenBSD: README,v 1.13 2008/07/19 10:35:31 reyk Exp $ -$KAME: README,v 1.9 2002/05/09 14:10:06 itojun Exp $ - - -Introduction -============ - -FAITH is a IPv6-to-IPv4 TCP relay. It performs tcp relay just as some of -firewall-oriented gateway does, but between IPv6 and IPv4 with address -translation. -TCP connections has to be made from IPv6 node to IPv4 node. FAITH will -not relay connections for the opposite direction. -To perform relays, FAITH daemon needs to be executed on a router between -your local IPv6 site and outside IPv4 network. The daemon needs to be -invoked per each TCP services (TCP port number). - - IPv4 node "dest" = 123.4.5.6 - | - [[[[ outside IPv4 ocean ]]]] - | - node that runs FAITH-daemon (usually a router) - | - ==+=====+===+==== IPv6, or IPv4/v6 network in your site ^ - | | | connection - clients IPv6 node "src" | - -You will have to allocate an IPv6 address prefix to map IPv4 addresses into. -The following description uses 2001:db8:ffff:0000:: as example. -Please use a prefix which belongs to your site. -FAITH will make it possible to make a IPv6 TCP connection From IPv6 node -"src", toward IPv4 node "dest", by specifying FAITH-mapped address -2001:db8:ffff:0000::123.4.5.6 -(which is, 2001:db8:ffff:0000:0000:0000:7b04:0506). -The address mapping can be performed by hand:-), by special nameserver on -the network, or by special resolver on the source node. - - -Setup -===== - -The following example assumes: -- You have assigned 2001:db8:ffff:0000:: as FAITH address prefix. -- You are willing to provide IPv6-to IPv4 TCP relay for telnet. - -<<On the translating router on which faithd runs>> - -(1) If you have IPv6 TCP server for the "telnet" service, i.e. telnetd via - inet6d, disable that daemon. Comment out the line from "inet6d.conf" - and send the HUP signal to "inet6d". - -(2) Execute sysctl as root to enable FAITH support in the kernel. - - # sysctl net.inet6.ip6.keepfaith=1 - -(3) Route packets toward FAITH prefix into "faith0" interface. - - # ifconfig faith0 up - # route add -inet6 2001:db8:ffff:0000:: -prefixlen 64 ::1 - # route change -inet6 2001:db8:ffff:0000:: -prefixlen 64 -ifp faith0 - -(4) Execute "faithd" by root as follows: - - # faithd telnet /usr/libexec/telnetd telnetd - - 1st argument is a service name you are willing to provide TCP relay. - (it can be specified either by number "23" or by string "telnet") - 2nd argument is a path name for local IPv6 TCP server. If there is a - connection toward the router itself, this program will be invoked. - 3rd and the following arguments are arguments for the local IPv6 TCP - server. (3rd argument is typically the program name without its path.) - - More examples: - - # faithd ftpd /usr/libexec/ftpd ftpd -l - # faithd sshd - -If inetd(8) on your platform have special support for faithd, it is possible -to setup faithd services via inetd(8). Consult manpage for details. - - -<<Routing>> - -(4) Make sure that packets whose destinations match the prefix can -reach from the IPv6 host to the translating router. - -<<On the IPv6 host>> - -There are two ways to translate IPv4 address to IPv6 address: - (a) Faked by DNS - (b) Faked by /etc/hosts. - -(5.a) Install "newbie" and set up FAITH mode. See kit/ports/newbie. - -(5.b) Add an entry into /etc/hosts so that you can resolve hostname into -faked IPv6 address. For example, add the following line for www.netbsd.org: - - 2001:db8:ffff:0000::140.160.140.252 www.netbsd.org - -<<On the translating router on which faithd runs.>> - -(6) To see if "faithd" works, watch "/var/log/daemon". Note: please -setup "/etc/syslog.conf" so that LOG_DAEMON messages are to be stored -in "/var/log/daemon". - - <e.g.> - daemon.* /var/log/daemon - - -Access control -============== - -Since faithd implements TCP relaying service, it is critical to implement -proper access control to cope with malicious use. Bad guy may try to -use your relay router to circumvent access controls, or may try to -abuse your network (like sending SPAMs from IPv4 address that belong to you). -Install IPv6 packet filter directives that would reject traffic from -unwanted source. If you are using inetd-based setup, you may be able to -use access control mechanisms in inetd. - - -Advanced configuration -====================== - -If you would like to restrict IPv4 destination for translation, you may -want to do the following: - - # route add -inet6 2001:db8:ffff:0000::123.0.0.0 -prefixlen 104 ::1 - # route change -inet6 2001:db8:ffff:0000::123.0.0.0 -prefixlen 104 \ - -ifp faith0 - -By this way, you can restrict IPv4 destination to 123.0.0.0/8. -You may also want to reject packets toward 2001:db8:ffff:0000::/64 which -is not in 2001:db8:ffff:0000::123.0.0.0/104. This will be left as excerside -for the reader. - -By doing this, you will be able to provide your IPv4 web server to outside -IPv6 customers, without risks of unwanted open relays. - - [[[[ IPv6 network outside ]]]] | - | | connection - node that runs FAITH-daemon (usually a router) v - | - ========+======== IPv4/v6 network in your site - | (123.0.0.0/8) - IPv4 web server diff --git a/usr.sbin/faithd/faithd.8 b/usr.sbin/faithd/faithd.8 deleted file mode 100644 index 2dd68180ffb..00000000000 --- a/usr.sbin/faithd/faithd.8 +++ /dev/null @@ -1,330 +0,0 @@ -.\" $OpenBSD: faithd.8,v 1.37 2012/09/26 16:19:44 jmc Exp $ -.\" $KAME: faithd.8,v 1.36 2002/05/09 13:59:16 itojun Exp $ -.\" -.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. Neither the name of the project nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.Dd $Mdocdate: September 26 2012 $ -.Dt FAITHD 8 -.Os -.Sh NAME -.Nm faithd -.Nd FAITH IPv6/v4 translator daemon -.Sh SYNOPSIS -.Nm -.Op Fl dp -.Op Fl f Ar configfile -.Ar service -.Op Ar serverpath Op Ar serverargs -.\".Nm "" -.Sh DESCRIPTION -.Nm -provides an IPv6-to-IPv4 TCP relay. -.Nm -must be used on an IPv4/v6 dual stack router. -.Pp -When -.Nm -receives -.Tn TCPv6 -traffic, -.Nm -will relay the -.Tn TCPv6 -traffic to -.Tn TCPv4 . -The destination for the relayed -.Tn TCPv4 -connection is determined by the last 4 octets of the original -.Tn IPv6 -destination. -For example, if -.Li 2001:db8:4819:ffff:: -is reserved for -.Nm faithd , -and the -.Tn TCPv6 -destination address is -.Li 2001:db8:4819:ffff::0a01:0101 , -the traffic is relayed to IPv4 destination -.Li 10.1.1.1 . -.Pp -To use the -.Nm -translation service, -an IPv6 address prefix must be reserved for mapping IPv4 addresses onto. -The kernel must be properly configured to route all the TCP connections -toward the reserved IPv6 address prefix into the -.Xr faith 4 -pseudo interface, by using the -.Xr route 8 -command. -Also, -.Xr sysctl 8 -should be used to configure -.Dv net.inet6.ip6.keepfaith -to -.Dv 1 . -.Pp -The router must be configured to capture all the TCP traffic -for a given reserved -.Tn IPv6 -address prefix, by using the -.Xr route 8 -and -.Xr sysctl 8 -commands. -.Pp -.Nm -needs a special name-to-address translation logic, so that -hostnames get resolved into a special -.Tn IPv6 -address prefix. -For small-scale installation, use -.Xr hosts 5 . -For large-scale installation, it is useful to have -a DNS server with special address translation support. -An implementation called -.Nm totd -is available -at -.Lk http://www.dillema.net/software/totd.html . -Make sure you do not propagate translated DNS records to normal DNS cloud, -it is highly harmful. -.\".Ss Daemon mode -When -.Nm -.\"is invoked as a stand-alone program, -is invoked, -.Nm -will daemonize itself. -.Nm -will listen to -.Tn TCPv6 -port -.Ar service . -If -.Tn TCPv6 -traffic to port -.Ar service -is found, it relays the connection. -.Pp -Since -.Nm -listens to TCP port -.Ar service , -it is not possible to run local TCP daemons for port -.Ar service -on the router, using -.Xr inetd 8 -or other standard mechanisms. -Local daemons can be run on the router -by specifying a -.Ar serverpath -to -.Nm faithd . -.Nm -will invoke a local daemon at -.Ar serverpath -if the destination address is a local interface address, -and will perform translation to IPv4 TCP in other cases. -.Ar serverargs -can also be specified as -arguments for the local daemon. -.Pp -The following options are available: -.Bl -tag -width indent -.It Fl d -Debugging information will be generated using -.Xr syslog 3 . -.It Fl f Ar configfile -Specify a configuration file for access control. -See below. -.It Fl p -Use the privileged TCP port number as a source port, -for an IPv4 TCP connection toward the final destination. -For relaying -.Xr ftp 1 -this flag is not necessary as special program code is supplied. -.El -.Pp -.Nm -will relay both normal and out-of-band TCP data. -It is capable of emulating TCP half close as well. -.Nm -includes special support for protocols used by -.Xr ftp 1 . -When translating FTP protocol, -.Nm -translates network level addresses in -.Li PORT/LPRT/EPRT -and -.Li PASV/LPSV/EPSV -commands. -.Pp -Inactive sessions will be disconnected in 30 minutes, -to avoid stale sessions from chewing up resources. -This may be inappropriate for some of the services -.Pq should this be configurable? . -.Ss Access control -To prevent malicious access, -.Nm -implements a simple address-based access control. -With -.Pa /etc/faithd.conf -.Po -or -.Ar configfile -specified by -.Fl f -.Pc , -.Nm -will avoid relaying unwanted traffic. -.Pa faithd.conf -contains directives with the following format: -.Bl -bullet -.It -.Xo -.Ar src/slen Li deny Ar dst/dlen -.Xc -.Pp -If the source address of a query matches -.Ar src/slen , -and the translated destination address matches -.Ar dst/dlen , -deny the connection. -.It -.Xo -.Ar src/slen Li permit Ar dst/dlen -.Xc -.Pp -If the source address of a query matches -.Ar src/slen , -and the translated destination address matches -.Ar dst/dlen , -permit the connection. -.El -.Pp -The directives are evaluated in sequence, -and the first matching entry will be effective. -If there is no match -.Pq the end of the ruleset has been reached , -the traffic is denied. -.\".Pp -.\"With inetd mode, -.\"traffic may be filtered by using access control functionality in -.\".Xr inetd 8 . -.Sh RETURN VALUES -.Nm -exits with -.Dv EXIT_SUCCESS -.Pq 0 -on success, and -.Dv EXIT_FAILURE -.Pq 1 -on error. -.Sh EXAMPLES -Before invoking -.Nm faithd , -the -.Xr faith 4 -interface has to be configured properly: -.Bd -literal -offset indent -# sysctl net.inet6.ip6.accept_rtadv=0 -# sysctl net.inet6.ip6.forwarding=1 -# sysctl net.inet6.ip6.keepfaith=1 -# ifconfig faith0 up -# route add -inet6 2001:db8:4819:ffff:: -prefixlen 96 ::1 -# route change -inet6 2001:db8:4819:ffff:: -prefixlen 96 -ifp faith0 -.Ed -.\".Ss Daemon mode samples -.Pp -To translate -.Li telnet -service, and provide no local telnet service, invoke -.Nm -as follows: -.Pp -.Dl # faithd telnet -.Pp -Pass extra arguments to the local daemon: -.Pp -.Dl # faithd ftp /usr/libexec/ftpd ftpd -l -.Ss Access control samples -The following illustrates a simple -.Pa faithd.conf -setting. -.Bd -literal -offset indent -# Permit anyone from 2001:db8:ffff::/48 to use the translator, -# to connect to the following IPv4 destinations: -# - any location except 10.0.0.0/8 and 127.0.0.0/8. -# Permit no other connections. -# -2001:db8:ffff::/48 deny 10.0.0.0/8 -2001:db8:ffff::/48 deny 127.0.0.0/8 -2001:db8:ffff::/48 permit 0.0.0.0/0 -.Ed -.Sh SEE ALSO -.Xr faith 4 , -.Xr route 8 , -.Xr sysctl 8 -.Sh STANDARDS -.Rs -.%A J. Hagino -.%A K. Yamamoto -.%D June 2001 -.%R RFC 3142 -.%T "An IPv6-to-IPv4 Transport Relay Translator" -.Re -.\" -.Sh HISTORY -The -.Nm -command first appeared in the WIDE Hydrangea IPv6 protocol stack kit. -.\" -.Sh SECURITY CONSIDERATIONS -It is very insecure to use IP-address-based authentication -for connections relayed by -.Nm . -.Pp -Administrators are advised to limit access to -.Nm -using -.Pa faithd.conf , -or by using IPv6 packet filters, -to protect the -.Nm -service from malicious parties and avoid theft of service/bandwidth. -IPv6 destination addresses can be limited by -carefully configuring routing entries that point to -.Xr faith 4 , -using -.Xr route 8 . -IPv6 source addresses need to be filtered using a packet filter. -The documents listed in -.Sx SEE ALSO -have more discussions on this topic. diff --git a/usr.sbin/faithd/faithd.c b/usr.sbin/faithd/faithd.c deleted file mode 100644 index 8d0df583a06..00000000000 --- a/usr.sbin/faithd/faithd.c +++ /dev/null @@ -1,885 +0,0 @@ -/* $OpenBSD: faithd.c,v 1.31 2011/03/02 04:56:59 deraadt Exp $ */ -/* $KAME: faithd.c,v 1.58 2002/09/08 01:12:30 itojun Exp $ */ - -/* - * Copyright (C) 1997 and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * User level translator from IPv6 to IPv4. - * - * Usage: faithd [<port> <progpath> <arg1(progname)> <arg2> ...] - * e.g. faithd telnet /usr/libexec/telnetd telnetd - */ - -#include <sys/param.h> -#include <sys/types.h> -#include <sys/sysctl.h> -#include <sys/socket.h> -#include <sys/wait.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/ioctl.h> -#ifdef __FreeBSD__ -#include <libutil.h> -#endif - -#include <poll.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> -#include <errno.h> -#include <signal.h> -#include <fcntl.h> -#include <termios.h> - -#include <net/if_types.h> -#ifdef IFT_FAITH -# define USE_ROUTE -# include <net/if.h> -# include <net/route.h> -# include <net/if_dl.h> -#endif - -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <ifaddrs.h> - -#include "faithd.h" -#include "prefix.h" - -char *serverpath = NULL; -char *serverarg[MAXARGV + 1]; -static char *faithdname = NULL; -char logname[BUFSIZ]; -char procname[BUFSIZ]; - -struct myaddrs { - struct myaddrs *next; - struct sockaddr *addr; -}; -struct myaddrs *myaddrs = NULL; - -static const char *service; -#ifdef USE_ROUTE -static int sockfd = 0; -#endif -int dflag = 0; -static int pflag = 0; -static int inetd = 0; -static char *configfile = NULL; - -int main(int, char **); -#if 0 -static int inetd_main(int, char **); -#endif -static int daemon_main(int, char **); -static void play_service(int); -static void play_child(int, struct sockaddr *); -static int faith_prefix(struct sockaddr *); -static int map6to4(struct sockaddr_in6 *, struct sockaddr_in *); -static void sig_child(int); -static void sig_terminate(int); -static void start_daemon(void); -static void exit_stderr(const char *, ...) - __attribute__((__format__(__printf__, 1, 2))); -static void grab_myaddrs(void); -static void free_myaddrs(void); -static void update_myaddrs(void); -static void usage(void); - -int -main(int argc, char **argv) -{ - - /* - * Initializing stuff - */ - - faithdname = strrchr(argv[0], '/'); - if (faithdname) - faithdname++; - else - faithdname = argv[0]; - -#if 0 - if (strcmp(faithdname, "faithd") != 0) { - inetd = 1; - return inetd_main(argc, argv); - } else - return daemon_main(argc, argv); -#else - return daemon_main(argc, argv); -#endif -} - -#if 0 -static int -inetd_main(int argc, char **argv) -{ - char path[MAXPATHLEN]; - struct sockaddr_storage me; - struct sockaddr_storage from; - socklen_t melen, fromlen; - int i; - int error; - const int on = 1; - char sbuf[NI_MAXSERV], snum[NI_MAXSERV]; - - if (config_load(configfile) < 0 && configfile) { - exit_failure("could not load config file"); - /*NOTREACHED*/ - } - - if (strrchr(argv[0], '/') == NULL) - snprintf(path, sizeof(path), "%s/%s", DEFAULT_DIR, argv[0]); - else - snprintf(path, sizeof(path), "%s", argv[0]); - -#ifdef USE_ROUTE - grab_myaddrs(); - - sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); - if (sockfd < 0) { - exit_failure("socket(PF_ROUTE): %s", strerror(errno)); - /*NOTREACHED*/ - } -#endif - - melen = sizeof(me); - if (getsockname(STDIN_FILENO, (struct sockaddr *)&me, &melen) < 0) { - exit_failure("getsockname: %s", strerror(errno)); - /*NOTREACHED*/ - } - fromlen = sizeof(from); - if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0) { - exit_failure("getpeername: %s", strerror(errno)); - /*NOTREACHED*/ - } - if (getnameinfo((struct sockaddr *)&me, melen, NULL, 0, - sbuf, sizeof(sbuf), NI_NUMERICHOST) == 0) - service = sbuf; - else - service = DEFAULT_PORT_NAME; - if (getnameinfo((struct sockaddr *)&me, melen, NULL, 0, - snum, sizeof(snum), NI_NUMERICHOST) != 0) - snprintf(snum, sizeof(snum), "?"); - - snprintf(logname, sizeof(logname), "faithd %s", snum); - snprintf(procname, sizeof(procname), "accepting port %s", snum); - openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); - - if (argc >= MAXARGV) { - exit_failure("too many arguments"); - /*NOTREACHED*/ - } - serverarg[0] = serverpath = path; - for (i = 1; i < argc; i++) - serverarg[i] = argv[i]; - serverarg[i] = NULL; - - error = setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &on, - sizeof(on)); - if (error < 0) { - exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno)); - /*NOTREACHED*/ - } - - play_child(STDIN_FILENO, (struct sockaddr *)&from); - exit_failure("should not reach here"); - return 0; /*dummy!*/ -} -#endif - -static int -daemon_main(int argc, char **argv) -{ - struct addrinfo hints, *res; - int s_wld, error, i, serverargc, on = 1; - int family = AF_INET6; - int c; - - while ((c = getopt(argc, argv, "df:p")) != -1) { - switch (c) { - case 'd': - dflag++; - break; - case 'f': - configfile = optarg; - break; - case 'p': - pflag++; - break; - default: - usage(); - /*NOTREACHED*/ - } - } - argc -= optind; - argv += optind; - - if (config_load(configfile) < 0 && configfile) { - exit_failure("could not load config file"); - /*NOTREACHED*/ - } - - -#ifdef USE_ROUTE - grab_myaddrs(); -#endif - - switch (argc) { - case 0: - usage(); - /*NOTREACHED*/ - default: - serverargc = argc - NUMARG; - if (serverargc >= MAXARGV) - exit_stderr("too many arguments"); - - serverpath = strdup(argv[NUMPRG]); - if (!serverpath) - exit_stderr("not enough core"); - for (i = 0; i < serverargc; i++) { - serverarg[i] = strdup(argv[i + NUMARG]); - if (!serverarg[i]) - exit_stderr("not enough core"); - } - serverarg[i] = NULL; - /* fall throuth */ - case 1: /* no local service */ - service = argv[NUMPRT]; - break; - } - - start_daemon(); - - /* - * Opening wild card socket for this service. - */ - - memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_PASSIVE; - hints.ai_family = family; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - error = getaddrinfo(NULL, service, &hints, &res); - if (error) - exit_failure("getaddrinfo: %s", gai_strerror(error)); - - s_wld = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (s_wld == -1) - exit_failure("socket: %s", strerror(errno)); - -#ifdef IPV6_FAITH - if (res->ai_family == AF_INET6) { - error = setsockopt(s_wld, IPPROTO_IPV6, IPV6_FAITH, &on, sizeof(on)); - if (error == -1) - exit_failure("setsockopt(IPV6_FAITH): %s", - strerror(errno)); - } -#endif - - error = setsockopt(s_wld, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - if (error == -1) - exit_failure("setsockopt(SO_REUSEADDR): %s", strerror(errno)); - - error = setsockopt(s_wld, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)); - if (error == -1) - exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno)); - -#ifdef IPV6_V6ONLY - error = setsockopt(s_wld, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); - if (error == -1) - exit_failure("setsockopt(IPV6_V6ONLY): %s", strerror(errno)); -#endif - - error = bind(s_wld, (struct sockaddr *)res->ai_addr, res->ai_addrlen); - if (error == -1) - exit_failure("bind: %s", strerror(errno)); - - error = listen(s_wld, 5); - if (error == -1) - exit_failure("listen: %s", strerror(errno)); - -#ifdef USE_ROUTE - sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); - if (sockfd < 0) { - exit_failure("socket(PF_ROUTE): %s", strerror(errno)); - /*NOTREACHED*/ - } -#endif - - /* - * Everything is OK. - */ - - snprintf(logname, sizeof(logname), "faithd %s", service); - snprintf(procname, sizeof(procname), "accepting port %s", service); - openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); - syslog(LOG_INFO, "Starting faith daemon for %s port", service); - - play_service(s_wld); - /* NOTREACHED */ - exit(1); /*pacify gcc*/ -} - -static void -play_service(int s_wld) -{ - struct sockaddr_storage srcaddr; - socklen_t len; - int s_src; - pid_t child_pid; - struct pollfd pfd[2]; - int error; - int maxfd; - - /* - * Wait, accept, fork, faith.... - */ -again: - setproctitle("%s", procname); - - pfd[0].fd = s_wld; - pfd[0].events = POLLIN; - pfd[1].revents = 0; - maxfd = 1; -#ifdef USE_ROUTE - if (sockfd) { - pfd[1].fd = sockfd; - pfd[1].events = POLLIN; - maxfd = 2; - } -#endif - - error = poll(pfd, maxfd, INFTIM); - if (error < 0) { - if (errno == EINTR) - goto again; - exit_failure("poll: %s", strerror(errno)); - /*NOTREACHED*/ - } - -#ifdef USE_ROUTE - if (pfd[1].revents & POLLIN) { - update_myaddrs(); - } -#endif - if (pfd[0].revents & POLLIN) { - len = sizeof(srcaddr); - s_src = accept(s_wld, (struct sockaddr *)&srcaddr, &len); - if (s_src < 0) { - if (errno == ECONNABORTED) - goto again; - exit_failure("socket: %s", strerror(errno)); - /*NOTREACHED*/ - } - if (srcaddr.ss_family == AF_INET6 && - IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&srcaddr)->sin6_addr)) { - close(s_src); - syslog(LOG_ERR, "connection from IPv4 mapped address?"); - goto again; - } - - child_pid = fork(); - - if (child_pid == 0) { - /* child process */ - close(s_wld); - closelog(); - openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); - play_child(s_src, (struct sockaddr *)&srcaddr); - exit_failure("should never reach here"); - /*NOTREACHED*/ - } else { - /* parent process */ - close(s_src); - if (child_pid == -1) - syslog(LOG_ERR, "can't fork"); - } - } - goto again; -} - -static void -play_child(int s_src, struct sockaddr *srcaddr) -{ - struct sockaddr_storage dstaddr6; - struct sockaddr_storage dstaddr4; - char src[NI_MAXHOST]; - char dst6[NI_MAXHOST]; - char dst4[NI_MAXHOST]; - socklen_t len = sizeof(dstaddr6); - int s_dst, error, hport, nresvport, on = 1; - struct timeval tv; - struct sockaddr *sa4; - const struct config *conf; - - tv.tv_sec = 1; - tv.tv_usec = 0; - - getnameinfo(srcaddr, srcaddr->sa_len, - src, sizeof(src), NULL, 0, NI_NUMERICHOST); - syslog(LOG_INFO, "accepted a client from %s", src); - - error = getsockname(s_src, (struct sockaddr *)&dstaddr6, &len); - if (error == -1) { - exit_failure("getsockname: %s", strerror(errno)); - /*NOTREACHED*/ - } - - getnameinfo((struct sockaddr *)&dstaddr6, len, - dst6, sizeof(dst6), NULL, 0, NI_NUMERICHOST); - syslog(LOG_INFO, "the client is connecting to %s", dst6); - - if (!faith_prefix((struct sockaddr *)&dstaddr6)) { - if (serverpath) { - /* - * Local service - */ - syslog(LOG_INFO, "executing local %s", serverpath); - if (!inetd) { - dup2(s_src, 0); - close(s_src); - dup2(0, 1); - dup2(0, 2); - } - execv(serverpath, serverarg); - syslog(LOG_ERR, "execv %s: %s", serverpath, - strerror(errno)); - _exit(EXIT_FAILURE); - } else { - close(s_src); - exit_success("no local service for %s", service); - } - } - - /* - * Act as a translator - */ - - switch (((struct sockaddr *)&dstaddr6)->sa_family) { - case AF_INET6: - if (!map6to4((struct sockaddr_in6 *)&dstaddr6, - (struct sockaddr_in *)&dstaddr4)) { - close(s_src); - exit_failure("map6to4 failed"); - /*NOTREACHED*/ - } - syslog(LOG_INFO, "translating from v6 to v4"); - break; - default: - close(s_src); - exit_failure("family not supported"); - /*NOTREACHED*/ - } - - sa4 = (struct sockaddr *)&dstaddr4; - getnameinfo(sa4, sa4->sa_len, - dst4, sizeof(dst4), NULL, 0, NI_NUMERICHOST); - - conf = config_match(srcaddr, sa4); - if (!conf || !conf->permit) { - close(s_src); - if (conf) { - exit_failure("translation to %s not permitted for %s", - dst4, prefix_string(&conf->match)); - /*NOTREACHED*/ - } else { - exit_failure("translation to %s not permitted", dst4); - /*NOTREACHED*/ - } - } - - syslog(LOG_INFO, "the translator is connecting to %s", dst4); - - setproctitle("port %s, %s -> %s", service, src, dst4); - - if (sa4->sa_family == AF_INET6) - hport = ntohs(((struct sockaddr_in6 *)&dstaddr4)->sin6_port); - else /* AF_INET */ - hport = ntohs(((struct sockaddr_in *)&dstaddr4)->sin_port); - - if (pflag) - s_dst = rresvport_af(&nresvport, sa4->sa_family); - else - s_dst = socket(sa4->sa_family, SOCK_STREAM, 0); - if (s_dst < 0) { - exit_failure("socket: %s", strerror(errno)); - /*NOTREACHED*/ - } - - if (conf->src.a.ss_family) { - if (bind(s_dst, (const struct sockaddr *)&conf->src.a, - conf->src.a.ss_len) < 0) { - exit_failure("bind: %s", strerror(errno)); - /*NOTREACHED*/ - } - } - - error = setsockopt(s_dst, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)); - if (error < 0) { - exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno)); - /*NOTREACHED*/ - } - - error = setsockopt(s_src, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); - if (error < 0) { - exit_failure("setsockopt(SO_SNDTIMEO): %s", strerror(errno)); - /*NOTREACHED*/ - } - error = setsockopt(s_dst, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); - if (error < 0) { - exit_failure("setsockopt(SO_SNDTIMEO): %s", strerror(errno)); - /*NOTREACHED*/ - } - - error = connect(s_dst, sa4, sa4->sa_len); - if (error < 0) { - exit_failure("connect: %s", strerror(errno)); - /*NOTREACHED*/ - } - - switch (hport) { - case FTP_PORT: - ftp_relay(s_src, s_dst); - break; - default: - tcp_relay(s_src, s_dst, service); - break; - } - - /* NOTREACHED */ -} - -/* 0: non faith, 1: faith */ -static int -faith_prefix(struct sockaddr *dst) -{ -#ifndef USE_ROUTE - int mib[4], size; - struct in6_addr faith_prefix; - struct sockaddr_in6 *dst6 = (struct sockaddr_in *)dst; - - if (dst->sa_family != AF_INET6) - return 0; - - mib[0] = CTL_NET; - mib[1] = PF_INET6; - mib[2] = IPPROTO_IPV6; - mib[3] = IPV6CTL_FAITH_PREFIX; - size = sizeof(struct in6_addr); - if (sysctl(mib, 4, &faith_prefix, &size, NULL, 0) < 0) { - exit_failure("sysctl: %s", strerror(errno)); - /*NOTREACHED*/ - } - - if (memcmp(dst, &faith_prefix, - sizeof(struct in6_addr) - sizeof(struct in_addr) == 0) { - return 1; - } - return 0; -#else - struct myaddrs *p; - struct sockaddr_in6 *sin6; - struct sockaddr_in *sin4; - struct sockaddr_in6 *dst6; - struct sockaddr_in *dst4; - struct sockaddr_in dstmap; - - dst6 = (struct sockaddr_in6 *)dst; - if (dst->sa_family == AF_INET6 && - IN6_IS_ADDR_V4MAPPED(&dst6->sin6_addr)) { - /* ugly... */ - memset(&dstmap, 0, sizeof(dstmap)); - dstmap.sin_family = AF_INET; - dstmap.sin_len = sizeof(dstmap); - memcpy(&dstmap.sin_addr, &dst6->sin6_addr.s6_addr[12], - sizeof(dstmap.sin_addr)); - dst = (struct sockaddr *)&dstmap; - } - - dst6 = (struct sockaddr_in6 *)dst; - dst4 = (struct sockaddr_in *)dst; - - for (p = myaddrs; p; p = p->next) { - sin6 = (struct sockaddr_in6 *)p->addr; - sin4 = (struct sockaddr_in *)p->addr; - - if (p->addr->sa_len != dst->sa_len || - p->addr->sa_family != dst->sa_family) - continue; - - switch (dst->sa_family) { - case AF_INET6: - if (sin6->sin6_scope_id == dst6->sin6_scope_id && - IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &dst6->sin6_addr)) - return 0; - break; - case AF_INET: - if (sin4->sin_addr.s_addr == dst4->sin_addr.s_addr) - return 0; - break; - } - } - return 1; -#endif -} - -/* 0: non faith, 1: faith */ -static int -map6to4(struct sockaddr_in6 *dst6, struct sockaddr_in *dst4) -{ - memset(dst4, 0, sizeof(*dst4)); - dst4->sin_len = sizeof(*dst4); - dst4->sin_family = AF_INET; - dst4->sin_port = dst6->sin6_port; - memcpy(&dst4->sin_addr, &dst6->sin6_addr.s6_addr[12], - sizeof(dst4->sin_addr)); - - if (dst4->sin_addr.s_addr == INADDR_ANY || - dst4->sin_addr.s_addr == INADDR_BROADCAST || - IN_MULTICAST(ntohl(dst4->sin_addr.s_addr))) - return 0; - return 1; -} - - -static void -sig_child(int sig) -{ - int save_errno = errno, status; - struct syslog_data sdata = SYSLOG_DATA_INIT; - pid_t pid; - - while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0) { - if (pid && WEXITSTATUS(status)) - syslog_r(LOG_WARNING, &sdata, - "child %ld exit status 0x%x", (long)pid, status); - } - - errno = save_errno; -} - -void -sig_terminate(int sig) -{ - struct syslog_data sdata = SYSLOG_DATA_INIT; - - syslog_r(LOG_INFO, &sdata, "Terminating faith daemon"); - _exit(EXIT_SUCCESS); -} - -static void -start_daemon(void) -{ -#ifdef SA_NOCLDWAIT - struct sigaction sa; -#endif - - if (daemon(0, 0) == -1) - exit_stderr("daemon: %s", strerror(errno)); - -#ifdef SA_NOCLDWAIT - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = sig_child; - sa.sa_flags = SA_NOCLDWAIT; - sigemptyset(&sa.sa_mask); - sigaction(SIGCHLD, &sa, (struct sigaction *)0); -#else - if (signal(SIGCHLD, sig_child) == SIG_ERR) { - exit_failure("signal CHLD: %s", strerror(errno)); - /*NOTREACHED*/ - } -#endif - - if (signal(SIGTERM, sig_terminate) == SIG_ERR) { - exit_failure("signal TERM: %s", strerror(errno)); - /*NOTREACHED*/ - } -} - -static void -exit_stderr(const char *fmt, ...) -{ - va_list ap; - char buf[BUFSIZ]; - - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - fprintf(stderr, "%s\n", buf); - exit(EXIT_FAILURE); -} - -void -exit_failure(const char *fmt, ...) -{ - va_list ap; - char buf[BUFSIZ]; - - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - syslog(LOG_ERR, "%s", buf); - exit(EXIT_FAILURE); -} - -void -exit_success(const char *fmt, ...) -{ - struct syslog_data sdata = SYSLOG_DATA_INIT; - va_list ap; - char buf[BUFSIZ]; - - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - syslog_r(LOG_INFO, &sdata, "%s", buf); - _exit(EXIT_SUCCESS); -} - -#ifdef USE_ROUTE -static void -grab_myaddrs() -{ - struct ifaddrs *ifap, *ifa; - struct myaddrs *p; - struct sockaddr_in6 *sin6; - - if (getifaddrs(&ifap) != 0) { - exit_failure("getifaddrs"); - /*NOTREACHED*/ - } - - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - switch (ifa->ifa_addr->sa_family) { - case AF_INET: - case AF_INET6: - break; - default: - continue; - } - - p = (struct myaddrs *)malloc(sizeof(struct myaddrs) + - ifa->ifa_addr->sa_len); - if (!p) { - exit_failure("not enough core"); - /*NOTREACHED*/ - } - memcpy(p + 1, ifa->ifa_addr, ifa->ifa_addr->sa_len); - p->next = myaddrs; - p->addr = (struct sockaddr *)(p + 1); -#ifdef __KAME__ - if (ifa->ifa_addr->sa_family == AF_INET6) { - sin6 = (struct sockaddr_in6 *)p->addr; - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || - IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { - sin6->sin6_scope_id = - ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); - sin6->sin6_addr.s6_addr[2] = 0; - sin6->sin6_addr.s6_addr[3] = 0; - } - } -#endif - myaddrs = p; - if (dflag) { - char hbuf[NI_MAXHOST]; - - getnameinfo(p->addr, p->addr->sa_len, - hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST); - syslog(LOG_INFO, "my interface: %s %s", hbuf, - ifa->ifa_name); - } - } - - freeifaddrs(ifap); -} - -static void -free_myaddrs() -{ - struct myaddrs *p, *q; - - p = myaddrs; - while (p) { - q = p->next; - free(p); - p = q; - } - myaddrs = NULL; -} - -static void -update_myaddrs() -{ - char msg[BUFSIZ]; - int len; - struct rt_msghdr *rtm; - - len = read(sockfd, msg, sizeof(msg)); - if (len < 0) { - syslog(LOG_ERR, "read(PF_ROUTE) failed"); - return; - } - rtm = (struct rt_msghdr *)msg; - if (len < 4 || len < rtm->rtm_msglen) { - syslog(LOG_ERR, "read(PF_ROUTE) short read"); - return; - } - if (rtm->rtm_version != RTM_VERSION) - return; - switch (rtm->rtm_type) { - case RTM_NEWADDR: - case RTM_DELADDR: - case RTM_IFINFO: - break; - default: - return; - } - /* XXX more filters here? */ - - syslog(LOG_INFO, "update interface address list"); - free_myaddrs(); - grab_myaddrs(); -} -#endif /*USE_ROUTE*/ - -static void -usage() -{ - fprintf(stderr, - "usage: %s [-dp] [-f configfile] service [serverpath [serverargs]]\n", - faithdname); - exit(0); -} diff --git a/usr.sbin/faithd/faithd.h b/usr.sbin/faithd/faithd.h deleted file mode 100644 index 633bd97b108..00000000000 --- a/usr.sbin/faithd/faithd.h +++ /dev/null @@ -1,67 +0,0 @@ -/* $OpenBSD: faithd.h,v 1.9 2007/08/21 22:18:41 krw Exp $ */ -/* $KAME: faithd.h,v 1.9 2002/05/09 09:41:24 itojun Exp $ */ - -/* - * Copyright (C) 1997 and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -extern char logname[]; -extern int dflag; - -extern void tcp_relay(int, int, const char *); -extern void ftp_relay(int, int); -extern int ftp_active(int, int, int *, int *); -extern int ftp_passive(int, int, int *, int *); -extern void exit_success(const char *, ...) - __attribute__((__format__(__printf__, 1, 2))); -extern void exit_failure(const char *, ...) - __attribute__((__format__(__printf__, 1, 2))); - -#define DEFAULT_PORT_NAME "telnet" -#define DEFAULT_DIR "/usr/libexec" -#define DEFAULT_NAME "telnetd" -#define DEFAULT_PATH (DEFAULT_DIR "/" DEFAULT_NAME) - -#define FTP_PORT 21 - -#define RETURN_SUCCESS 0 -#define RETURN_FAILURE 1 - -#define YES 1 -#define NO 0 - -#define MSS 2048 -#define MAXARGV 20 - -#define NUMPRT 0 -#define NUMPRG 1 -#define NUMARG 2 - -#define UC(b) (((int)b)&0xff) - -#define FAITH_TIMEOUT (30 * 60) /*second*/ diff --git a/usr.sbin/faithd/ftp.c b/usr.sbin/faithd/ftp.c deleted file mode 100644 index 474521f0a33..00000000000 --- a/usr.sbin/faithd/ftp.c +++ /dev/null @@ -1,953 +0,0 @@ -/* $OpenBSD: ftp.c,v 1.15 2007/03/20 04:00:32 tedu Exp $ */ -/* $KAME: ftp.c,v 1.20 2002/09/08 01:12:30 itojun Exp $ */ - -/* - * Copyright (C) 1997 and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <sys/time.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> -#include <poll.h> -#include <errno.h> -#include <ctype.h> - -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> - -#include "faithd.h" - -static char rbuf[MSS]; -static char sbuf[MSS]; -static int passivemode = 0; -static int wport4 = -1; /* listen() to active */ -static int wport6 = -1; /* listen() to passive */ -static int port4 = -1; /* active: inbound passive: outbound */ -static int port6 = -1; /* active: outbound passive: inbound */ -static struct sockaddr_storage data4; /* server data address */ -static struct sockaddr_storage data6; /* client data address */ -static int epsvall = 0; - -enum state { NONE, LPRT, EPRT, LPSV, EPSV }; - -static int ftp_activeconn(void); -static int ftp_passiveconn(void); -static int ftp_copy(int, int); -static int ftp_copyresult(int, int, enum state); -static int ftp_copycommand(int, int, enum state *); - -void -ftp_relay(int ctl6, int ctl4) -{ - struct pollfd pfd[6]; - int error; - enum state state = NONE; - struct timeval tv; - - syslog(LOG_INFO, "starting ftp control connection"); - - for (;;) { - int maxfd = 0; - - pfd[0].fd = ctl4; - pfd[0].events = POLLIN; - pfd[1].fd = ctl6; - pfd[1].events = POLLIN; - - maxfd = (ctl6 > maxfd) ? ctl6 : maxfd; - if (0 <= port4) { - pfd[2].fd = port4; - pfd[2].events = POLLIN; - } else - pfd[2].fd = -1; - - if (0 <= port6) { - pfd[3].fd = port6; - pfd[3].events = POLLIN; - } else - pfd[3].fd = -1; -#if 0 - if (0 <= wport4) { - pfd[4].fd = wport4; - pfd[4].events = POLLIN; - } else - pfd[4].fd = -1; - if (0 <= wport6) { - pfd[5].fd = wport6; - pfd[5].events = POLLIN; - } else - pfd[5].fd = -1; -#endif - tv.tv_sec = FAITH_TIMEOUT; - tv.tv_usec = 0; - - error = poll(pfd, 6, FAITH_TIMEOUT * 1000); - if (error == -1) - exit_failure("poll: %s", strerror(errno)); - else if (error == 0) - exit_failure("connection timeout"); - - /* - * The order of the following checks does (slightly) matter. - * It is important to visit all checks (do not use "continue"), - * otherwise some of the pipe may become full and we cannot - * relay correctly. - */ - if (pfd[1].revents & POLLIN) { - /* - * copy control connection from the client. - * command translation is necessary. - */ - error = ftp_copycommand(ctl6, ctl4, &state); - - if (error < 0) - goto bad; - else if (error == 0) { - close(ctl4); - close(ctl6); - exit_success("terminating ftp control connection"); - /*NOTREACHED*/ - } - } - if (pfd[1].revents & POLLIN) { - /* - * copy control connection from the server - * translation of result code is necessary. - */ - error = ftp_copyresult(ctl4, ctl6, state); - - if (error < 0) - goto bad; - else if (error == 0) { - close(ctl4); - close(ctl6); - exit_success("terminating ftp control connection"); - /*NOTREACHED*/ - } - } - if (0 <= port4 && 0 <= port6 && (pfd[2].revents & POLLIN)) { - /* - * copy data connection. - * no special treatment necessary. - */ - if (pfd[2].revents & POLLIN) - error = ftp_copy(port4, port6); - switch (error) { - case -1: - goto bad; - case 0: - close(port4); - close(port6); - port4 = port6 = -1; - syslog(LOG_INFO, "terminating data connection"); - break; - default: - break; - } - } - if (0 <= port4 && 0 <= port6 && (pfd[3].revents & POLLIN)) { - /* - * copy data connection. - * no special treatment necessary. - */ - if (pfd[3].revents & POLLIN) - error = ftp_copy(port6, port4); - switch (error) { - case -1: - goto bad; - case 0: - close(port4); - close(port6); - port4 = port6 = -1; - syslog(LOG_INFO, "terminating data connection"); - break; - default: - break; - } - } -#if 0 - if (wport4 && (pfd[4].revents & POLLIN)) { - /* - * establish active data connection from the server. - */ - ftp_activeconn(); - } - if (wport6 && (pfd[5].revents & POLLIN)) { - /* - * establish passive data connection from the client. - */ - ftp_passiveconn(); - } -#endif - } - - bad: - exit_failure("%s", strerror(errno)); -} - -static int -ftp_activeconn() -{ - socklen_t n; - int error; - struct pollfd pfd[1]; - struct sockaddr *sa; - - /* get active connection from server */ - pfd[0].fd = wport4; - pfd[0].events = POLLIN; - n = sizeof(data4); - if (poll(pfd, 1, 120 * 1000) == 0 - || (port4 = accept(wport4, (struct sockaddr *)&data4, &n)) < 0) { - close(wport4); - wport4 = -1; - syslog(LOG_INFO, "active mode data connection failed"); - return -1; - } - - /* ask active connection to client */ - sa = (struct sockaddr *)&data6; - port6 = socket(sa->sa_family, SOCK_STREAM, 0); - if (port6 == -1) { - close(port4); - close(wport4); - port4 = wport4 = -1; - syslog(LOG_INFO, "active mode data connection failed"); - return -1; - } - error = connect(port6, sa, sa->sa_len); - if (error < 0) { - close(port6); - close(port4); - close(wport4); - port6 = port4 = wport4 = -1; - syslog(LOG_INFO, "active mode data connection failed"); - return -1; - } - - syslog(LOG_INFO, "active mode data connection established"); - return 0; -} - -static int -ftp_passiveconn() -{ - socklen_t len; - int error; - struct pollfd pfd[1]; - struct sockaddr *sa; - - /* get passive connection from client */ - pfd[0].fd = wport6; - pfd[0].events = POLLIN; - len = sizeof(data6); - if (poll(pfd, 1, 120 * 1000) == 0 - || (port6 = accept(wport6, (struct sockaddr *)&data6, &len)) < 0) { - close(wport6); - wport6 = -1; - syslog(LOG_INFO, "passive mode data connection failed"); - return -1; - } - - /* ask passive connection to server */ - sa = (struct sockaddr *)&data4; - port4 = socket(sa->sa_family, SOCK_STREAM, 0); - if (port4 == -1) { - close(wport6); - close(port6); - wport6 = port6 = -1; - syslog(LOG_INFO, "passive mode data connection failed"); - return -1; - } - error = connect(port4, sa, sa->sa_len); - if (error < 0) { - close(wport6); - close(port4); - close(port6); - wport6 = port4 = port6 = -1; - syslog(LOG_INFO, "passive mode data connection failed"); - return -1; - } - - syslog(LOG_INFO, "passive mode data connection established"); - return 0; -} - -static int -ftp_copy(int src, int dst) -{ - int error, atmark, n; - - /* OOB data handling */ - error = ioctl(src, SIOCATMARK, &atmark); - if (error != -1 && atmark == 1) { - n = read(src, rbuf, 1); - if (n == -1) - goto bad; - send(dst, rbuf, n, MSG_OOB); -#if 0 - n = read(src, rbuf, sizeof(rbuf)); - if (n == -1) - goto bad; - write(dst, rbuf, n); - return n; -#endif - } - - n = read(src, rbuf, sizeof(rbuf)); - switch (n) { - case -1: - case 0: - return n; - default: - write(dst, rbuf, n); - return n; - } - - bad: - exit_failure("%s", strerror(errno)); - /*NOTREACHED*/ - return 0; /* to make gcc happy */ -} - -static int -ftp_copyresult(int src, int dst, enum state state) -{ - int error, atmark, n; - socklen_t len; - char *param; - int code; - char *a, *p; - int i; - - /* OOB data handling */ - error = ioctl(src, SIOCATMARK, &atmark); - if (error != -1 && atmark == 1) { - n = read(src, rbuf, 1); - if (n == -1) - goto bad; - send(dst, rbuf, n, MSG_OOB); -#if 0 - n = read(src, rbuf, sizeof(rbuf)); - if (n == -1) - goto bad; - write(dst, rbuf, n); - return n; -#endif - } - - n = read(src, rbuf, sizeof(rbuf)); - if (n <= 0) - return n; - rbuf[n] = '\0'; - - /* - * parse argument - */ - p = rbuf; - for (i = 0; i < 3; i++) { - if (!isdigit(*p)) { - /* invalid reply */ - write(dst, rbuf, n); - return n; - } - p++; - } - if (!isspace(*p)) { - /* invalid reply */ - write(dst, rbuf, n); - return n; - } - code = atoi(rbuf); - param = p; - /* param points to first non-command token, if any */ - while (isspace(*param)) - param++; - if (!*param) - param = NULL; - - switch (state) { - case NONE: - if (!passivemode && rbuf[0] == '1') { - if (ftp_activeconn() < 0) { - n = snprintf(rbuf, sizeof(rbuf), - "425 Cannot open data connetion\r\n"); - if (n < 0 || n >= sizeof(rbuf)) - n = 0; - } - } - if (n) - write(dst, rbuf, n); - return n; - case LPRT: - case EPRT: - /* expecting "200 PORT command successful." */ - if (code == 200) { - p = strstr(rbuf, "PORT"); - if (p) { - p[0] = (state == LPRT) ? 'L' : 'E'; - p[1] = 'P'; - } - } else { - close(wport4); - wport4 = -1; - } - write(dst, rbuf, n); - return n; - case LPSV: - case EPSV: - /* - * expecting "227 Entering Passive Mode (x,x,x,x,x,x,x)" - * (in some cases result comes without paren) - */ - if (code != 227) { -passivefail0: - close(wport6); - wport6 = -1; - write(dst, rbuf, n); - return n; - } - - { - unsigned int ho[4], po[2]; - struct sockaddr_in *sin; - struct sockaddr_in6 *sin6; - u_short port; - - /* - * PASV result -> LPSV/EPSV result - */ - p = param; - while (*p && *p != '(' && !isdigit(*p)) /*)*/ - p++; - if (!*p) - goto passivefail0; /*XXX*/ - if (*p == '(') /*)*/ - p++; - n = sscanf(p, "%u,%u,%u,%u,%u,%u", - &ho[0], &ho[1], &ho[2], &ho[3], &po[0], &po[1]); - if (n != 6) - goto passivefail0; /*XXX*/ - - /* keep PORT parameter */ - memset(&data4, 0, sizeof(data4)); - sin = (struct sockaddr_in *)&data4; - sin->sin_len = sizeof(*sin); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = 0; - for (n = 0; n < 4; n++) { - sin->sin_addr.s_addr |= - htonl((ho[n] & 0xff) << ((3 - n) * 8)); - } - sin->sin_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff)); - - /* get ready for passive data connection */ - memset(&data6, 0, sizeof(data6)); - sin6 = (struct sockaddr_in6 *)&data6; - sin6->sin6_len = sizeof(*sin6); - sin6->sin6_family = AF_INET6; - wport6 = socket(sin6->sin6_family, SOCK_STREAM, 0); - if (wport6 == -1) { -passivefail: - n = snprintf(sbuf, sizeof(sbuf), - "500 could not translate from PASV\r\n"); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(src, sbuf, n); - return n; - } -#ifdef IPV6_FAITH - { - int on = 1; - error = setsockopt(wport6, IPPROTO_IPV6, IPV6_FAITH, - &on, sizeof(on)); - if (error == -1) - exit_failure("setsockopt(IPV6_FAITH): %s", strerror(errno)); - } -#endif - error = bind(wport6, (struct sockaddr *)sin6, sin6->sin6_len); - if (error == -1) { - close(wport6); - wport6 = -1; - goto passivefail; - } - error = listen(wport6, 1); - if (error == -1) { - close(wport6); - wport6 = -1; - goto passivefail; - } - - /* transmit LPSV or EPSV */ - /* - * addr from dst, port from wport6 - */ - len = sizeof(data6); - error = getsockname(wport6, (struct sockaddr *)&data6, &len); - if (error == -1) { - close(wport6); - wport6 = -1; - goto passivefail; - } - sin6 = (struct sockaddr_in6 *)&data6; - port = sin6->sin6_port; - - len = sizeof(data6); - error = getsockname(dst, (struct sockaddr *)&data6, &len); - if (error == -1) { - close(wport6); - wport6 = -1; - goto passivefail; - } - sin6 = (struct sockaddr_in6 *)&data6; - sin6->sin6_port = port; - - if (state == LPSV) { - a = (char *)&sin6->sin6_addr; - p = (char *)&sin6->sin6_port; - n = snprintf(sbuf, sizeof(sbuf), -"228 Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)\r\n", - 6, 16, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), - UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]), - UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]), - UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]), - 2, UC(p[0]), UC(p[1])); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(dst, sbuf, n); - passivemode = 1; - return n; - } else { - n = snprintf(sbuf, sizeof(sbuf), -"229 Entering Extended Passive Mode (|||%d|)\r\n", - ntohs(sin6->sin6_port)); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(dst, sbuf, n); - passivemode = 1; - return n; - } - } - } - - bad: - exit_failure("%s", strerror(errno)); - /*NOTREACHED*/ - return 0; /* to make gcc happy */ -} - -static int -ftp_copycommand(int src, int dst, enum state *state) -{ - int error, atmark, n; - socklen_t len; - unsigned int af, hal, ho[16], pal, po[2]; - char *a, *p, *q; - char cmd[5], *param; - struct sockaddr_in *sin; - struct sockaddr_in6 *sin6; - enum state nstate; - char ch; - int i; - - /* OOB data handling */ - error = ioctl(src, SIOCATMARK, &atmark); - if (error != -1 && atmark == 1) { - n = read(src, rbuf, 1); - if (n == -1) - goto bad; - send(dst, rbuf, n, MSG_OOB); -#if 0 - n = read(src, rbuf, sizeof(rbuf)); - if (n == -1) - goto bad; - write(dst, rbuf, n); - return n; -#endif - } - - n = read(src, rbuf, sizeof(rbuf)); - if (n <= 0) - return n; - rbuf[n] = '\0'; - - if (n < 4) { - write(dst, rbuf, n); - return n; - } - - /* - * parse argument - */ - p = rbuf; - q = cmd; - for (i = 0; i < 4; i++) { - if (!isalpha(*p)) { - /* invalid command */ - write(dst, rbuf, n); - return n; - } - *q++ = islower(*p) ? toupper(*p) : *p; - p++; - } - if (!isspace(*p)) { - /* invalid command */ - write(dst, rbuf, n); - return n; - } - *q = '\0'; - param = p; - /* param points to first non-command token, if any */ - while (isspace(*param)) - param++; - if (!*param) - param = NULL; - - *state = NONE; - - if (strcmp(cmd, "LPRT") == 0 && param) { - /* - * LPRT -> PORT - */ - nstate = LPRT; - - close(wport4); - close(wport6); - close(port4); - close(port6); - wport4 = wport6 = port4 = port6 = -1; - - if (epsvall) { - n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n", - cmd); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(src, sbuf, n); - return n; - } - - n = sscanf(param, -"%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u", - &af, &hal, &ho[0], &ho[1], &ho[2], &ho[3], - &ho[4], &ho[5], &ho[6], &ho[7], - &ho[8], &ho[9], &ho[10], &ho[11], - &ho[12], &ho[13], &ho[14], &ho[15], - &pal, &po[0], &po[1]); - if (n != 21 || af != 6 || hal != 16|| pal != 2) { - n = snprintf(sbuf, sizeof(sbuf), - "501 illegal parameter to LPRT\r\n"); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(src, sbuf, n); - return n; - } - - /* keep LPRT parameter */ - memset(&data6, 0, sizeof(data6)); - sin6 = (struct sockaddr_in6 *)&data6; - sin6->sin6_len = sizeof(*sin6); - sin6->sin6_family = AF_INET6; - for (n = 0; n < 16; n++) - sin6->sin6_addr.s6_addr[n] = ho[n]; - sin6->sin6_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff)); - -sendport: - /* get ready for active data connection */ - len = sizeof(data4); - error = getsockname(dst, (struct sockaddr *)&data4, &len); - if (error == -1) { -lprtfail: - n = snprintf(sbuf, sizeof(sbuf), - "500 could not translate to PORT\r\n"); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(src, sbuf, n); - return n; - } - if (((struct sockaddr *)&data4)->sa_family != AF_INET) - goto lprtfail; - sin = (struct sockaddr_in *)&data4; - sin->sin_port = 0; - wport4 = socket(sin->sin_family, SOCK_STREAM, 0); - if (wport4 == -1) - goto lprtfail; - error = bind(wport4, (struct sockaddr *)sin, sin->sin_len); - if (error == -1) { - close(wport4); - wport4 = -1; - goto lprtfail; - } - error = listen(wport4, 1); - if (error == -1) { - close(wport4); - wport4 = -1; - goto lprtfail; - } - - /* transmit PORT */ - len = sizeof(data4); - error = getsockname(wport4, (struct sockaddr *)&data4, &len); - if (error == -1) { - close(wport4); - wport4 = -1; - goto lprtfail; - } - if (((struct sockaddr *)&data4)->sa_family != AF_INET) { - close(wport4); - wport4 = -1; - goto lprtfail; - } - sin = (struct sockaddr_in *)&data4; - a = (char *)&sin->sin_addr; - p = (char *)&sin->sin_port; - n = snprintf(sbuf, sizeof(sbuf), "PORT %d,%d,%d,%d,%d,%d\r\n", - UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), - UC(p[0]), UC(p[1])); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(dst, sbuf, n); - *state = nstate; - passivemode = 0; - return n; - } else if (strcmp(cmd, "EPRT") == 0 && param) { - /* - * EPRT -> PORT - */ - char *afp, *hostp, *portp; - struct addrinfo hints, *res; - - nstate = EPRT; - - close(wport4); - close(wport6); - close(port4); - close(port6); - wport4 = wport6 = port4 = port6 = -1; - - if (epsvall) { - n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n", - cmd); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(src, sbuf, n); - return n; - } - - p = param; - ch = *p++; /* boundary character */ - afp = p; - while (*p && *p != ch) - p++; - if (!*p) { -eprtparamfail: - n = snprintf(sbuf, sizeof(sbuf), - "501 illegal parameter to EPRT\r\n"); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(src, sbuf, n); - return n; - } - *p++ = '\0'; - hostp = p; - while (*p && *p != ch) - p++; - if (!*p) - goto eprtparamfail; - *p++ = '\0'; - portp = p; - while (*p && *p != ch) - p++; - if (!*p) - goto eprtparamfail; - *p++ = '\0'; - - n = sscanf(afp, "%d", &af); - if (n != 1 || af != 2) { - n = snprintf(sbuf, sizeof(sbuf), - "501 unsupported address family to EPRT\r\n"); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(src, sbuf, n); - return n; - } - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - error = getaddrinfo(hostp, portp, &hints, &res); - if (error) { - n = snprintf(sbuf, sizeof(sbuf), - "501 EPRT: %s\r\n", gai_strerror(error)); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(src, sbuf, n); - return n; - } - if (res->ai_next) { - n = snprintf(sbuf, sizeof(sbuf), - "501 EPRT: %s resolved to multiple addresses\r\n", hostp); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(src, sbuf, n); - freeaddrinfo(res); - return n; - } - - memcpy(&data6, res->ai_addr, res->ai_addrlen); - - freeaddrinfo(res); - goto sendport; - } else if (strcmp(cmd, "LPSV") == 0 && !param) { - /* - * LPSV -> PASV - */ - nstate = LPSV; - - close(wport4); - close(wport6); - close(port4); - close(port6); - wport4 = wport6 = port4 = port6 = -1; - - if (epsvall) { - n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n", - cmd); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(src, sbuf, n); - return n; - } - - /* transmit PASV */ - n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n"); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(dst, sbuf, n); - *state = LPSV; - passivemode = 0; /* to be set to 1 later */ - return n; - } else if (strcmp(cmd, "EPSV") == 0 && !param) { - /* - * EPSV -> PASV - */ - close(wport4); - close(wport6); - close(port4); - close(port6); - wport4 = wport6 = port4 = port6 = -1; - - n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n"); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(dst, sbuf, n); - *state = EPSV; - passivemode = 0; /* to be set to 1 later */ - return n; - } else if (strcmp(cmd, "EPSV") == 0 && param - && strncasecmp(param, "ALL", 3) == 0 && isspace(param[3])) { - /* - * EPSV ALL - */ - epsvall = 1; - n = snprintf(sbuf, sizeof(sbuf), "200 EPSV ALL command successful.\r\n"); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(src, sbuf, n); - return n; - } else if (strcmp(cmd, "PORT") == 0 || strcmp(cmd, "PASV") == 0) { - /* - * reject PORT/PASV - */ - n = snprintf(sbuf, sizeof(sbuf), "502 %s not implemented.\r\n", cmd); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(src, sbuf, n); - return n; - } else if (passivemode - && (strcmp(cmd, "STOR") == 0 - || strcmp(cmd, "STOU") == 0 - || strcmp(cmd, "RETR") == 0 - || strcmp(cmd, "LIST") == 0 - || strcmp(cmd, "NLST") == 0 - || strcmp(cmd, "APPE") == 0)) { - /* - * commands with data transfer. need to care about passive - * mode data connection. - */ - - if (ftp_passiveconn() < 0) { - n = snprintf(sbuf, sizeof(sbuf), "425 Cannot open data connetion\r\n"); - if (n < 0 || n >= sizeof(sbuf)) - n = 0; - if (n) - write(src, sbuf, n); - } else { - /* simply relay the command */ - write(dst, rbuf, n); - } - - *state = NONE; - return n; - } else { - /* simply relay it */ - *state = NONE; - write(dst, rbuf, n); - return n; - } - - bad: - exit_failure("%s", strerror(errno)); - /*NOTREACHED*/ - return 0; /* to make gcc happy */ -} diff --git a/usr.sbin/faithd/prefix.c b/usr.sbin/faithd/prefix.c deleted file mode 100644 index 3ad8e58fa0a..00000000000 --- a/usr.sbin/faithd/prefix.c +++ /dev/null @@ -1,349 +0,0 @@ -/* $OpenBSD: prefix.c,v 1.7 2003/09/02 23:27:55 itojun Exp $ */ -/* $KAME: prefix.c,v 1.13 2003/09/02 22:50:17 itojun Exp $ */ - -/* - * Copyright (C) 2000 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <stddef.h> -#include <stdlib.h> -#include <limits.h> - -#ifndef offsetof -#define offsetof(type, member) ((size_t)(u_long)(&((type *)0)->member)) -#endif - -#include "faithd.h" -#include "prefix.h" - -static int prefix_set(const char *, struct prefix *, int); -static struct config *config_load1(const char *); -#if 0 -static void config_show1(const struct config *); -static void config_show(void); -#endif - -struct config *config_list = NULL; -const int niflags = NI_NUMERICHOST; - -static int -prefix_set(const char *s, struct prefix *prefix, int slash) -{ - char *p = NULL, *q, *r; - struct addrinfo hints, *res = NULL; - int max; - char *a; - - p = strdup(s); - if (!p) - goto fail; - q = strchr(p, '/'); - if (q) { - if (!slash) - goto fail; - *q++ = '\0'; - } - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; /*dummy*/ - hints.ai_flags = AI_NUMERICHOST; - if (getaddrinfo(p, "0", &hints, &res)) - goto fail; - if (res->ai_next || res->ai_addrlen > sizeof(prefix->a)) - goto fail; - memcpy(&prefix->a, res->ai_addr, res->ai_addrlen); - - switch (prefix->a.ss_family) { - case AF_INET: - max = 32; - a = (char *)&((struct sockaddr_in *)&prefix->a)->sin_addr; - break; - case AF_INET6: - max = 128; - a = (char *)&((struct sockaddr_in6 *)&prefix->a)->sin6_addr; - break; - default: - a = NULL; - max = -1; - break; - } - - if (q) { - r = NULL; - prefix->l = (int)strtoul(q, &r, 10); - if (!*q || *r) - goto fail; - if (prefix->l < 0 || prefix->l > max) - goto fail; - } else - prefix->l = max; - - if (p) - free(p); - if (res) - freeaddrinfo(res); - return 0; - -fail: - if (p) - free(p); - if (res) - freeaddrinfo(res); - return -1; -} - -const char * -prefix_string(const struct prefix *prefix) -{ - static char buf[NI_MAXHOST + 20]; - char hbuf[NI_MAXHOST]; - - if (getnameinfo((const struct sockaddr *)&prefix->a, prefix->a.ss_len, - hbuf, sizeof(hbuf), NULL, 0, niflags)) - return NULL; - snprintf(buf, sizeof(buf), "%s/%d", hbuf, prefix->l); - return buf; -} - -int -prefix_match(const struct prefix *prefix, const struct sockaddr *sa) -{ - struct sockaddr_storage a, b; - char *pa, *pb; - int off, l; - - if (prefix->a.ss_family != sa->sa_family || - prefix->a.ss_len != sa->sa_len) - return 0; - - if (prefix->a.ss_len > sizeof(a) || sa->sa_len > sizeof(b)) - return 0; - - switch (prefix->a.ss_family) { - case AF_INET: - off = offsetof(struct sockaddr_in, sin_addr); - break; - case AF_INET6: - off = offsetof(struct sockaddr_in6, sin6_addr); - break; - default: - if (memcmp(&prefix->a, sa, prefix->a.ss_len) != 0) - return 0; - else - return 1; - } - - memcpy(&a, &prefix->a, prefix->a.ss_len); - memcpy(&b, sa, sa->sa_len); - l = prefix->l / 8 + (prefix->l % 8 ? 1 : 0); - - /* overrun check */ - if (off + l > a.ss_len) - return 0; - - pa = ((char *)&a) + off; - pb = ((char *)&b) + off; - if (prefix->l % 8) { - pa[prefix->l / 8] &= 0xff00 >> (prefix->l % 8); - pb[prefix->l / 8] &= 0xff00 >> (prefix->l % 8); - } - if (memcmp(pa, pb, l) != 0) - return 0; - else - return 1; -} - -/* - * prefix/prefixlen permit/deny prefix/prefixlen [srcaddr] - * 3ffe::/16 permit 10.0.0.0/8 10.1.1.1 - */ -static struct config * -config_load1(const char *line) -{ - struct config *conf; - char buf[BUFSIZ]; - char *p; - char *token[4]; - int i; - - if (strlen(line) + 1 > sizeof(buf)) - return NULL; - strlcpy(buf, line, sizeof(buf)); - - p = strchr(buf, '\n'); - if (!p) - return NULL; - *p = '\0'; - p = strchr(buf, '#'); - if (p) - *p = '\0'; - if (strlen(buf) == 0) - return NULL; - - p = buf; - memset(token, 0, sizeof(token)); - for (i = 0; i < sizeof(token) / sizeof(token[0]); i++) { - token[i] = strtok(p, "\t "); - p = NULL; - if (token[i] == NULL) - break; - } - /* extra tokens? */ - if (strtok(p, "\t ") != NULL) - return NULL; - /* insufficient tokens */ - switch (i) { - case 3: - case 4: - break; - default: - return NULL; - } - - conf = (struct config *)malloc(sizeof(*conf)); - if (conf == NULL) - return NULL; - memset(conf, 0, sizeof(*conf)); - - if (strcasecmp(token[1], "permit") == 0) - conf->permit = 1; - else if (strcasecmp(token[1], "deny") == 0) - conf->permit = 0; - else { - /* invalid keyword is considered as "deny" */ - conf->permit = 0; - } - - if (prefix_set(token[0], &conf->match, 1) < 0) - goto fail; - if (prefix_set(token[2], &conf->dest, 1) < 0) - goto fail; - if (token[3]) { - if (prefix_set(token[3], &conf->src, 0) < 0) - goto fail; - } - - return conf; - -fail: - free(conf); - return NULL; -} - -int -config_load(const char *configfile) -{ - FILE *fp; - char buf[BUFSIZ]; - struct config *conf, *p; - struct config sentinel; - - config_list = NULL; - - if (!configfile) - configfile = _PATH_PREFIX_CONF; - fp = fopen(configfile, "r"); - if (fp == NULL) - return -1; - - p = &sentinel; - sentinel.next = NULL; - while (fgets(buf, sizeof(buf), fp) != NULL) { - conf = config_load1(buf); - if (conf) { - p->next = conf; - p = p->next; - } - } - config_list = sentinel.next; - - fclose(fp); - return 0; -} - -#if 0 -static void -config_show1(const struct config *conf) -{ - const char *p; - - p = prefix_string(&conf->match); - printf("%s", p ? p : "?"); - - if (conf->permit) - printf(" permit"); - else - printf(" deny"); - - p = prefix_string(&conf->dest); - printf(" %s", p ? p : "?"); - - printf("\n"); -} - -static void -config_show() -{ - struct config *conf; - - for (conf = config_list; conf; conf = conf->next) - config_show1(conf); -} -#endif - -const struct config * -config_match(struct sockaddr *sa1, struct sockaddr *sa2) -{ - static struct config conf; - const struct config *p; - - if (sa1->sa_len > sizeof(conf.match.a) || - sa2->sa_len > sizeof(conf.dest.a)) - return NULL; - - memset(&conf, 0, sizeof(conf)); - if (!config_list) { - conf.permit = 1; - memcpy(&conf.match.a, sa1, sa1->sa_len); - memcpy(&conf.dest.a, sa2, sa2->sa_len); - return &conf; - } - - for (p = config_list; p; p = p->next) - if (prefix_match(&p->match, sa1) && prefix_match(&p->dest, sa2)) - return p; - - return NULL; -} diff --git a/usr.sbin/faithd/prefix.h b/usr.sbin/faithd/prefix.h deleted file mode 100644 index b8d930ea76c..00000000000 --- a/usr.sbin/faithd/prefix.h +++ /dev/null @@ -1,52 +0,0 @@ -/* $OpenBSD: prefix.h,v 1.2 2002/02/16 21:28:02 millert Exp $ */ -/* $KAME: prefix.h,v 1.3 2000/11/19 11:45:38 itojun Exp $ */ - -/* - * Copyright (C) 2000 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -struct prefix { - struct sockaddr_storage a; - int l; -}; - -struct config { - struct config *next; - - int permit; - struct prefix match; - struct prefix dest; - struct prefix src; /* src to use for outgoing connection */ -}; - -#define _PATH_PREFIX_CONF "/etc/faithd.conf" - -extern const char *prefix_string(const struct prefix *); -extern int prefix_match(const struct prefix *, const struct sockaddr *); -extern int config_load(const char *); -extern const struct config *config_match(struct sockaddr *, struct sockaddr *); diff --git a/usr.sbin/faithd/tcp.c b/usr.sbin/faithd/tcp.c deleted file mode 100644 index 8982b63b474..00000000000 --- a/usr.sbin/faithd/tcp.c +++ /dev/null @@ -1,327 +0,0 @@ -/* $OpenBSD: tcp.c,v 1.12 2002/09/08 01:20:15 itojun Exp $ */ -/* $KAME: tcp.c,v 1.10 2002/08/20 23:01:01 itojun Exp $ */ - -/* - * Copyright (C) 1997 and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <sys/time.h> -#include <sys/wait.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> - -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> - -#include "faithd.h" - -static char tcpbuf[16*1024]; - /* bigger than MSS and may be lesser than window size */ -static int tblen, tboff, oob_exists; -static fd_set readfds, writefds, exceptfds; -static char atmark_buf[2]; -static pid_t cpid = (pid_t)0; -static pid_t ppid = (pid_t)0; -volatile time_t child_lastactive = (time_t)0; -static time_t parent_lastactive = (time_t)0; - -static void sig_ctimeout(int); -static void sig_child(int); -static void notify_inactive(void); -static void notify_active(void); -static void send_data(int, int, const char *, int); -static void relay(int, int, const char *, int); - -/* - * Inactivity timer: - * - child side (ppid != 0) will send SIGUSR1 to parent every (FAITH_TIMEOUT/4) - * second if traffic is active. if traffic is inactive, don't send SIGUSR1. - * - parent side (ppid == 0) will check the last SIGUSR1 it have seen. - */ -static void -sig_ctimeout(int sig) -{ - int save_errno = errno; - struct syslog_data sdata = SYSLOG_DATA_INIT; - - /* parent side: record notification from the child */ - if (dflag) - syslog_r(LOG_DEBUG, &sdata, "activity timer from child"); - child_lastactive = time(NULL); - errno = save_errno; -} - -/* parent will terminate if child dies. */ -static void -sig_child(int sig) -{ - struct syslog_data sdata = SYSLOG_DATA_INIT; - int status; - pid_t pid; - - pid = wait3(&status, WNOHANG, (struct rusage *)0); - if (pid > 0 && WEXITSTATUS(status)) - syslog_r(LOG_WARNING, &sdata, - "child %ld exit status 0x%x", (long)pid, status); - exit_success("terminate connection due to child termination"); -} - -static void -notify_inactive() -{ - time_t t; - - /* only on parent side... */ - if (ppid) - return; - - /* parent side should check for timeout. */ - t = time(NULL); - if (dflag) { - syslog(LOG_DEBUG, "parent side %sactive, child side %sactive", - (FAITH_TIMEOUT < t - parent_lastactive) ? "in" : "", - (FAITH_TIMEOUT < t - child_lastactive) ? "in" : ""); - } - - if (FAITH_TIMEOUT < t - child_lastactive - && FAITH_TIMEOUT < t - parent_lastactive) { - /* both side timeouted */ - signal(SIGCHLD, SIG_DFL); - kill(cpid, SIGTERM); - wait(NULL); - exit_failure("connection timeout"); - /* NOTREACHED */ - } -} - -static void -notify_active() -{ - if (ppid) { - /* child side: notify parent of active traffic */ - time_t t; - t = time(NULL); - if (FAITH_TIMEOUT / 4 < t - child_lastactive) { - if (kill(ppid, SIGUSR1) < 0) { - exit_failure("terminate connection due to parent termination"); - /* NOTREACHED */ - } - child_lastactive = t; - } - } else { - /* parent side */ - parent_lastactive = time(NULL); - } -} - -static void -send_data(int s_rcv, int s_snd, const char *service, int direction) -{ - int cc; - - if (oob_exists) { - cc = send(s_snd, atmark_buf, 1, MSG_OOB); - if (cc == -1) - goto retry_or_err; - oob_exists = 0; - if (s_rcv >= FD_SETSIZE) - exit_failure("descriptor too big"); - FD_SET(s_rcv, &exceptfds); - } - - for (; tboff < tblen; tboff += cc) { - cc = write(s_snd, tcpbuf + tboff, tblen - tboff); - if (cc < 0) - goto retry_or_err; - } -#ifdef DEBUG - if (tblen) { - if (tblen >= sizeof(tcpbuf)) - tblen = sizeof(tcpbuf) - 1; - tcpbuf[tblen] = '\0'; - syslog(LOG_DEBUG, "from %s (%dbytes): %s", - direction == 1 ? "client" : "server", tblen, tcpbuf); - } -#endif /* DEBUG */ - tblen = 0; tboff = 0; - if (s_snd >= FD_SETSIZE) - exit_failure("descriptor too big"); - FD_CLR(s_snd, &writefds); - if (s_rcv >= FD_SETSIZE) - exit_failure("descriptor too big"); - FD_SET(s_rcv, &readfds); - return; - retry_or_err: - if (errno != EAGAIN) - exit_failure("writing relay data failed: %s", strerror(errno)); - if (s_snd >= FD_SETSIZE) - exit_failure("descriptor too big"); - FD_SET(s_snd, &writefds); -} - -static void -relay(int s_rcv, int s_snd, const char *service, int direction) -{ - int atmark, error, maxfd; - struct timeval tv; - fd_set oreadfds, owritefds, oexceptfds; - - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_ZERO(&exceptfds); - fcntl(s_snd, F_SETFD, O_NONBLOCK); - oreadfds = readfds; owritefds = writefds; oexceptfds = exceptfds; - if (s_rcv >= FD_SETSIZE) - exit_failure("descriptor too big"); - FD_SET(s_rcv, &readfds); - FD_SET(s_rcv, &exceptfds); - oob_exists = 0; - maxfd = (s_rcv > s_snd) ? s_rcv : s_snd; - - for (;;) { - tv.tv_sec = FAITH_TIMEOUT / 4; - tv.tv_usec = 0; - oreadfds = readfds; - owritefds = writefds; - oexceptfds = exceptfds; - error = select(maxfd + 1, &readfds, &writefds, &exceptfds, &tv); - if (error == -1) { - if (errno == EINTR) - continue; - exit_failure("select: %s", strerror(errno)); - } else if (error == 0) { - readfds = oreadfds; - writefds = owritefds; - exceptfds = oexceptfds; - notify_inactive(); - continue; - } - - /* activity notification */ - notify_active(); - - if (FD_ISSET(s_rcv, &exceptfds)) { - error = ioctl(s_rcv, SIOCATMARK, &atmark); - if (error != -1 && atmark == 1) { - int cc; - oob_read_retry: - cc = read(s_rcv, atmark_buf, 1); - if (cc == 1) { - if (s_rcv >= FD_SETSIZE) - exit_failure("descriptor too big"); - FD_CLR(s_rcv, &exceptfds); - if (s_snd >= FD_SETSIZE) - exit_failure("descriptor too big"); - FD_SET(s_snd, &writefds); - oob_exists = 1; - } else if (cc == -1) { - if (errno == EINTR) - goto oob_read_retry; - exit_failure("reading oob data failed" - ": %s", - strerror(errno)); - } - } - } - if (FD_ISSET(s_rcv, &readfds)) { - relaydata_read_retry: - tblen = read(s_rcv, tcpbuf, sizeof(tcpbuf)); - tboff = 0; - - switch (tblen) { - case -1: - if (errno == EINTR) - goto relaydata_read_retry; - exit_failure("reading relay data failed: %s", - strerror(errno)); - /* NOTREACHED */ - case 0: - /* to close opposite-direction relay process */ - shutdown(s_snd, 0); - - close(s_rcv); - close(s_snd); - exit_success("terminating %s relay", service); - /* NOTREACHED */ - default: - if (s_rcv >= FD_SETSIZE) - exit_failure("descriptor too big"); - FD_CLR(s_rcv, &readfds); - if (s_snd >= FD_SETSIZE) - exit_failure("descriptor too big"); - FD_SET(s_snd, &writefds); - break; - } - } - if (FD_ISSET(s_snd, &writefds)) - send_data(s_rcv, s_snd, service, direction); - } -} - -void -tcp_relay(int s_src, int s_dst, const char *service) -{ - syslog(LOG_INFO, "starting %s relay", service); - - child_lastactive = parent_lastactive = time(NULL); - - cpid = fork(); - switch (cpid) { - case -1: - exit_failure("tcp_relay: can't fork grand child: %s", - strerror(errno)); - /* NOTREACHED */ - case 0: - /* child process: relay going traffic */ - ppid = getppid(); - /* this is child so reopen log */ - closelog(); - openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); - relay(s_src, s_dst, service, 1); - /* NOTREACHED */ - default: - /* parent process: relay coming traffic */ - ppid = (pid_t)0; - signal(SIGUSR1, sig_ctimeout); - signal(SIGCHLD, sig_child); - relay(s_dst, s_src, service, 0); - /* NOTREACHED */ - } -} |