add faithd, IPv6-to-IPv4 tcp relay translator.
utilizes pseudo-device "faith".
This commit is contained in:
parent
1e44889b75
commit
e5db40b6de
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: Makefile,v 1.119 1999/07/12 22:12:06 thorpej Exp $
|
||||
# $NetBSD: Makefile,v 1.120 1999/07/13 22:16:48 itojun Exp $
|
||||
# from: @(#)Makefile 5.20 (Berkeley) 6/12/93
|
||||
|
||||
# XXX Temporary for NO_SENDMAIL and BUILD_POSTFIX
|
||||
|
@ -25,8 +25,8 @@ SUBDIR= ac accton amd apm apmd arp bad144 bind bootp catman \
|
|||
zdump zic
|
||||
|
||||
# IPv6
|
||||
SUBDIR+=gifconfig ifmcstat mld6query ndp rip6query route6d rtadvd setkey \
|
||||
traceroute6
|
||||
SUBDIR+=faithd gifconfig ifmcstat mld6query ndp rip6query route6d rtadvd \
|
||||
setkey traceroute6
|
||||
|
||||
# ATM PVC
|
||||
SUBDIR+=pvcsif pvctxctl
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
# $NetBSD: Makefile,v 1.1 1999/07/13 22:16:49 itojun Exp $
|
||||
|
||||
PROG= faithd
|
||||
SRCS= faithd.c tcp.c ftp.c rsh.c
|
||||
MAN= faithd.8
|
||||
|
||||
#CFLAGS+= -DFAITH4
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -0,0 +1,139 @@
|
|||
Configuring FAITH IPv6-to-IPv4 TCP relay
|
||||
|
||||
Kazu Yamamoto and Jun-ichiro itojun Hagino
|
||||
$NetBSD: README,v 1.1 1999/07/13 22:16:49 itojun Exp $
|
||||
KAME Id: README,v 1.1.2.5.2.2.10.3 1999/03/31 04:40:42 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
|
||||
address translation.
|
||||
TCP connections has to be made from IPv6 node to 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 3ffe:0501:1234:ffff:: 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
|
||||
3ffe:0501:1234:ffff::123.4.5.6
|
||||
(which is, 3ffe:0501:1234:ffff:0000:0000:7b04:0506).
|
||||
The address mapping can be performed by hand:-), by speical nameserver on
|
||||
the network, or by special resolver on the source node.
|
||||
|
||||
|
||||
Setup
|
||||
=====
|
||||
|
||||
The following example assumes:
|
||||
- You have assigned 3ffe:0501:1234:ffff:: as FAITH adderss 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 -w net.inet6.ip6.keepfaith=1
|
||||
|
||||
(3) Route packets toward FAITH prefix into "faith0" interface.
|
||||
|
||||
# ifconfig faith0 up
|
||||
# route add -inet6 3ffe:0501:1234:ffff:: -prefixlen 64 -interface faith0
|
||||
|
||||
or, on platforms that has problem with "-interface":
|
||||
# ifconfig faith0 up
|
||||
# route add -inet6 3ffe:0501:1234:ffff:: -prefixlen 64 \
|
||||
fe80:q::xxxx:yyyy:zzzz:wwww
|
||||
(the last one is link-local address assigned for faith0)
|
||||
|
||||
(4) Execute "faithd" by root as follows:
|
||||
|
||||
# faithd telnet /usr/local/v6/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 login /usr/local/v6/libexec/rlogin rlogind
|
||||
# faithd shell /usr/local/v6/libexec/rshd rshd
|
||||
# faithd ftpd /usr/local/v6/libexec/ftpd ftpd -l
|
||||
# faithd sshd
|
||||
|
||||
|
||||
<<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 addrss. For example, add the following line for www.netbsd.org:
|
||||
|
||||
3ffe:0501:1234:ffff::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
|
||||
|
||||
|
||||
Advanced configuration
|
||||
======================
|
||||
|
||||
If you would like to restrict IPv4 destination for translation, you may
|
||||
want to do the following:
|
||||
|
||||
# route add -inet6 3ffe:0501:1234:ffff::123.0.0.0 -prefixlen 104 \
|
||||
-interface faith0
|
||||
|
||||
By this way, you can restrict IPv4 destination to 123.0.0.0/8.
|
||||
You may also want to reject packets toward 3ffe:0501:1234:ffff::/64 which
|
||||
is not in 3ffe:0501:1234:ffff::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
|
|
@ -0,0 +1,242 @@
|
|||
.\" 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.
|
||||
.\"
|
||||
.\" $NetBSD: faithd.8,v 1.1 1999/07/13 22:16:49 itojun Exp $
|
||||
.\" KAME Id: faithd.8,v 1.1.2.6.4.5.2.5 1999/03/31 04:40:46 itojun Exp
|
||||
.\"
|
||||
.Dd May 17, 1998
|
||||
.Dt FAITHD 8
|
||||
.Os KAME
|
||||
.Sh NAME
|
||||
.Nm faithd
|
||||
.Nd FAITH IPv6/v4 translator daemon
|
||||
.Sh SYNOPSIS
|
||||
.Nm faithd
|
||||
.Op Fl dp
|
||||
.Oo
|
||||
.Ar service
|
||||
.Oo
|
||||
.Ar serverpath
|
||||
.Op Ar serverargs
|
||||
.Oc
|
||||
.Oc
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
provides IPv6/v4 TCP relay for the specified
|
||||
.Ar service .
|
||||
.Pp
|
||||
.Nm
|
||||
must be invoked on IPv4/v6 dual stack router.
|
||||
The router must be configured to capture all the TCP traffic
|
||||
toward reserved IPv6 address prefix, by using
|
||||
.Xr route 8
|
||||
and
|
||||
.Xr sysctl 8
|
||||
commands.
|
||||
.Nm
|
||||
will daemonize itself on invocation.
|
||||
.Pp
|
||||
.Nm
|
||||
will listen to TCPv6 port
|
||||
.Ar service .
|
||||
If TCPv6 traffic to port
|
||||
.Ar service
|
||||
is found,
|
||||
.Nm
|
||||
will relay the TCPv6 traffic to TCPv4.
|
||||
Destination for relayed TCPv4 connection will be determined by the
|
||||
last 4 octets of the original IPv6 destination.
|
||||
For example, if
|
||||
.Li 3ffe:0501:4819:ffff::
|
||||
is reserved for
|
||||
.Nm faithd ,
|
||||
and the TCPv6 destination address is
|
||||
.Li 3ffe:0501:4819:ffff::0a01:0101 ,
|
||||
the traffic will be relayed to IPv4 destination
|
||||
.Li 10.1.1.1 .
|
||||
.Pp
|
||||
If
|
||||
.Ar service
|
||||
is not given,
|
||||
.Li telnet
|
||||
is assumed, and
|
||||
.Nm
|
||||
will relay TCP traffic on TCP port
|
||||
.Li telnet .
|
||||
With
|
||||
.Ar service ,
|
||||
.Nm
|
||||
will work as TCP relaying daemon for specified
|
||||
.Ar service
|
||||
as described above.
|
||||
.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.
|
||||
By specifying
|
||||
.Ar serverpath
|
||||
to
|
||||
.Nm faithd ,
|
||||
you can run local daemons on the router.
|
||||
.Nm
|
||||
will invoke local daemon at
|
||||
.Ar serverpath
|
||||
if the destination address is local interface address,
|
||||
and will perform translation to IPv4 TCP in other cases.
|
||||
You can also specify
|
||||
.Ar serverargs
|
||||
for the arguments for the local daemon.
|
||||
.Pp
|
||||
To use
|
||||
.Nm
|
||||
translation service,
|
||||
an IPv6 address prefix must be reserved for mapping IPv4 addresses into.
|
||||
Kernel must be properly configured to route all the TCP connection
|
||||
toward the reserved IPv6 address prefix into the
|
||||
.Dv faith
|
||||
pseudo interface, by using
|
||||
.Xr route 8
|
||||
command.
|
||||
Also,
|
||||
.Xr sysctl 8
|
||||
should be used to configure
|
||||
.Dv net.inet6.ip6.keepfaith
|
||||
to
|
||||
.Dv 1 .
|
||||
.Pp
|
||||
If
|
||||
.Fl d
|
||||
is given, debugging information will be generated using
|
||||
.Xr syslog 3 .
|
||||
If
|
||||
.Fl p
|
||||
is given,
|
||||
.Nm
|
||||
will use privileged TCP port number as source port,
|
||||
for IPv4 TCP connection toward final destination.
|
||||
For relaying
|
||||
.Xr ftp 1
|
||||
and
|
||||
.Xr rlogin 1 ,
|
||||
.Fl p
|
||||
is not necessary as special program code is supplied.
|
||||
.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
|
||||
and
|
||||
.Xr rlogin 1 .
|
||||
When translating FTP protocol,
|
||||
.Nm
|
||||
translates network level addresses in
|
||||
.Li PORT/LPRT/EPRT
|
||||
and
|
||||
.Li PASV/LPSV/EPSV
|
||||
commands.
|
||||
For RLOGIN protocol,
|
||||
.Nm
|
||||
will relay back connection from
|
||||
.Xr rogind 8
|
||||
on the server to
|
||||
.Xr rlogin 1
|
||||
on client.
|
||||
.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
|
||||
.Po
|
||||
should this be configurable?
|
||||
.Pc .
|
||||
.\"
|
||||
.Sh EXAMPLES
|
||||
To translate
|
||||
.Li telnet
|
||||
service, and provide no local telnet service, invoke
|
||||
.Nm
|
||||
as either of the following:
|
||||
.Bd -literal -offset
|
||||
# faithd
|
||||
# faithd telnet
|
||||
.Ed
|
||||
.Pp
|
||||
If you would like to provide local telnet service via
|
||||
.Xr telnetd 8
|
||||
on
|
||||
.Li /usr/local/v6/libexec/telnetd ,
|
||||
user the following command line:
|
||||
.Bd -literal -offset
|
||||
# faithd telnet /usr/local/v6/libexec/telnetd telnetd
|
||||
.Ed
|
||||
.Pp
|
||||
If you would like to pass extra arguments to the local daemon:
|
||||
.Bd -literal -offset
|
||||
# faithd ftpd /usr/local/v6/libexec/ftpd ftpd -l
|
||||
.Ed
|
||||
.Pp
|
||||
Here are some other examples:
|
||||
.Bd -literal -offset
|
||||
# faithd login /usr/local/v6/libexec/rlogin rlogind
|
||||
# faithd shell /usr/local/v6/libexec/rshd rshd
|
||||
# faithd sshd
|
||||
.Ed
|
||||
.\"
|
||||
.Sh RETURN VALUES
|
||||
.Nm
|
||||
exits with
|
||||
.Dv EXIT_SUCCESS
|
||||
.Pq 0
|
||||
on success, and
|
||||
.Dv EXIT_FAILURE
|
||||
.Pq 1
|
||||
on error.
|
||||
.\"
|
||||
.Sh SEE ALSO
|
||||
.Xr route 8 ,
|
||||
.Xr sysctl 8
|
||||
.\"
|
||||
.Sh SECURITY NOTICE
|
||||
It is very insecure to use
|
||||
.Xr rhosts 5
|
||||
and other IP-address based authentication, for connections relayed by
|
||||
.Nm
|
||||
.Po
|
||||
and any other TCP relaying services
|
||||
.Pc .
|
||||
.\"
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command first appeared in WIDE Hydrangea IPv6 protocol stack kit.
|
|
@ -0,0 +1,810 @@
|
|||
/* $NetBSD: faithd.c,v 1.1 1999/07/13 22:16:49 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/local/v6/sbin/telnetd telnetd
|
||||
*/
|
||||
|
||||
#define ss_len __ss_len
|
||||
#define ss_family __ss_family
|
||||
|
||||
#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 <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>
|
||||
|
||||
#ifdef FAITH4
|
||||
#include <resolv.h>
|
||||
#include <arpa/nameser.h>
|
||||
#ifndef FAITH_NS
|
||||
#define FAITH_NS "FAITH_NS"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "faithd.h"
|
||||
|
||||
char *serverpath = NULL;
|
||||
char *serverarg[MAXARGV + 1];
|
||||
static char *faithdname = NULL;
|
||||
char logname[BUFSIZ];
|
||||
struct myaddrs {
|
||||
struct myaddrs *next;
|
||||
struct sockaddr *addr;
|
||||
};
|
||||
struct myaddrs *myaddrs = NULL;
|
||||
static char *service;
|
||||
#ifdef USE_ROUTE
|
||||
static int sockfd = 0;
|
||||
#endif
|
||||
int dflag = 0;
|
||||
static int pflag = 0;
|
||||
|
||||
int main __P((int, char **));
|
||||
static void play_service __P((int));
|
||||
static void play_child __P((int, struct sockaddr *));
|
||||
static int faith_prefix __P((struct sockaddr *));
|
||||
static int map6to4 __P((struct sockaddr_in6 *, struct sockaddr_in *));
|
||||
#ifdef FAITH4
|
||||
static int map4to6 __P((struct sockaddr_in *, struct sockaddr_in6 *));
|
||||
#endif
|
||||
static void sig_child __P((int));
|
||||
static void sig_terminate __P((int));
|
||||
static void start_daemon __P((void));
|
||||
static unsigned int if_maxindex __P((void));
|
||||
static void grab_myaddrs __P((void));
|
||||
static void free_myaddrs __P((void));
|
||||
static void update_myaddrs __P((void));
|
||||
static void usage __P((void));
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct addrinfo hints, *res;
|
||||
int s_wld, error, i, serverargc, on = 1;
|
||||
int family = AF_INET6;
|
||||
int c;
|
||||
#ifdef FAITH_NS
|
||||
char *ns;
|
||||
#endif /* FAITH_NS */
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
||||
/*
|
||||
* Initializing stuff
|
||||
*/
|
||||
|
||||
faithdname = strrchr(argv[0], '/');
|
||||
if (faithdname)
|
||||
faithdname++;
|
||||
else
|
||||
faithdname = argv[0];
|
||||
|
||||
while ((c = getopt(argc, argv, "dp46")) != -1) {
|
||||
switch (c) {
|
||||
case 'd':
|
||||
dflag++;
|
||||
break;
|
||||
case 'p':
|
||||
pflag++;
|
||||
break;
|
||||
#ifdef FAITH4
|
||||
case '4':
|
||||
family = AF_INET;
|
||||
break;
|
||||
case '6':
|
||||
family = AF_INET6;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
#ifdef FAITH_NS
|
||||
if ((ns = getenv(FAITH_NS)) != NULL) {
|
||||
struct sockaddr_storage ss;
|
||||
struct addrinfo hints, *res;
|
||||
char serv[NI_MAXSERV];
|
||||
|
||||
memset(&ss, 0, sizeof(ss));
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
sprintf(serv, "%u", NAMESERVER_PORT);
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
if (getaddrinfo(ns, serv, &hints, &res) == 0) {
|
||||
res_init();
|
||||
memcpy(&_res_ext.nsaddr, res->ai_addr, res->ai_addrlen);
|
||||
_res.nscount = 1;
|
||||
}
|
||||
}
|
||||
#endif /* FAITH_NS */
|
||||
|
||||
#ifdef USE_ROUTE
|
||||
grab_myaddrs();
|
||||
#endif
|
||||
|
||||
switch (argc) {
|
||||
case 0:
|
||||
serverpath = DEFAULT_PATH;
|
||||
serverarg[0] = DEFAULT_NAME;
|
||||
serverarg[1] = NULL;
|
||||
service = DEFAULT_PORT_NAME;
|
||||
break;
|
||||
default:
|
||||
serverargc = argc - NUMARG;
|
||||
if (serverargc > MAXARGV)
|
||||
exit_error("too many augments");
|
||||
|
||||
serverpath = malloc(strlen(argv[NUMPRG]));
|
||||
strcpy(serverpath, argv[NUMPRG]);
|
||||
for (i = 0; i < serverargc; i++) {
|
||||
serverarg[i] = malloc(strlen(argv[i + NUMARG]));
|
||||
strcpy(serverarg[i], argv[i + NUMARG]);
|
||||
}
|
||||
serverarg[i] = NULL;
|
||||
/* fall throuth */
|
||||
case 1: /* no local service */
|
||||
service = argv[NUMPRT];
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 = 0;
|
||||
error = getaddrinfo(NULL, service, &hints, &res);
|
||||
if (error)
|
||||
exit_error("gaddrinfo: %s", gai_strerror(error));
|
||||
|
||||
s_wld = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
if (s_wld == -1)
|
||||
exit_error("socket: %s", ERRSTR);
|
||||
|
||||
#ifdef IPV6_FAITH
|
||||
if (res->ai_family == AF_INET6) {
|
||||
error = setsockopt(s_wld, IPPROTO_IPV6, IPV6_FAITH, &on, sizeof(on));
|
||||
if (error == -1)
|
||||
exit_error("setsockopt: %s", ERRSTR);
|
||||
}
|
||||
#endif
|
||||
#ifdef FAITH4
|
||||
#ifdef IP_FAITH
|
||||
if (res->ai_family == AF_INET) {
|
||||
error = setsockopt(s_wld, IPPROTO_IP, IP_FAITH, &on, sizeof(on));
|
||||
if (error == -1)
|
||||
exit_error("setsockopt: %s", ERRSTR);
|
||||
}
|
||||
#endif
|
||||
#endif /* FAITH4 */
|
||||
|
||||
error = setsockopt(s_wld, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||
if (error == -1)
|
||||
exit_error("setsockopt: %s", ERRSTR);
|
||||
|
||||
error = setsockopt(s_wld, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on));
|
||||
if (error == -1)
|
||||
exit_error("setsockopt: %s", ERRSTR);
|
||||
|
||||
error = bind(s_wld, (struct sockaddr *)res->ai_addr, res->ai_addrlen);
|
||||
if (error == -1)
|
||||
exit_error("bind: %s", ERRSTR);
|
||||
|
||||
error = listen(s_wld, 5);
|
||||
if (error == -1)
|
||||
exit_error("listen: %s", ERRSTR);
|
||||
|
||||
#ifdef USE_ROUTE
|
||||
sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC);
|
||||
if (sockfd < 0) {
|
||||
exit_error("socket(PF_ROUTE): %s", ERRSTR);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Everything is OK.
|
||||
*/
|
||||
|
||||
start_daemon();
|
||||
|
||||
sprintf(logname, "accepting port %s", service);
|
||||
openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
|
||||
syslog(LOG_INFO, "Staring faith daemon for %s port", service);
|
||||
|
||||
play_service(s_wld);
|
||||
/*NOTRECHED*/
|
||||
exit(1); /*pacify gcc*/
|
||||
}
|
||||
|
||||
static void
|
||||
play_service(int s_wld)
|
||||
{
|
||||
struct sockaddr_storage srcaddr;
|
||||
int len;
|
||||
int s_src;
|
||||
pid_t child_pid;
|
||||
fd_set rfds;
|
||||
int error;
|
||||
int maxfd;
|
||||
|
||||
/*
|
||||
* Wait, accept, fork, faith....
|
||||
*/
|
||||
again:
|
||||
setproctitle(logname);
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(s_wld, &rfds);
|
||||
maxfd = s_wld;
|
||||
#ifdef USE_ROUTE
|
||||
if (sockfd) {
|
||||
FD_SET(sockfd, &rfds);
|
||||
maxfd = (maxfd < sockfd) ? sockfd : maxfd;
|
||||
}
|
||||
#endif
|
||||
|
||||
error = select(maxfd + 1, &rfds, NULL, NULL, NULL);
|
||||
if (error < 0) {
|
||||
if (errno == EINTR)
|
||||
goto again;
|
||||
exit_failure("select: %s", ERRSTR);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
#ifdef USE_ROUTE
|
||||
if (FD_ISSET(sockfd, &rfds)) {
|
||||
update_myaddrs();
|
||||
}
|
||||
#endif
|
||||
if (FD_ISSET(s_wld, &rfds)) {
|
||||
len = sizeof(srcaddr);
|
||||
s_src = accept(s_wld, (struct sockaddr *)&srcaddr,
|
||||
&len);
|
||||
if (s_src == -1)
|
||||
exit_failure("socket: %s", ERRSTR);
|
||||
|
||||
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");
|
||||
} 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[MAXHOSTNAMELEN];
|
||||
char dst6[MAXHOSTNAMELEN];
|
||||
char dst4[MAXHOSTNAMELEN];
|
||||
int len = sizeof(dstaddr6);
|
||||
int s_dst, error, hport, nresvport, on = 1;
|
||||
struct timeval tv;
|
||||
|
||||
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", ERRSTR);
|
||||
|
||||
getnameinfo((struct sockaddr *)&dstaddr6, dstaddr6.__ss_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);
|
||||
dup2(s_src, 0);
|
||||
close(s_src);
|
||||
dup2(0, 1);
|
||||
dup2(0, 2);
|
||||
execv(serverpath, serverarg);
|
||||
syslog(LOG_ERR, "execv %s: %s", serverpath, ERRSTR);
|
||||
_exit(EXIT_FAILURE);
|
||||
} else {
|
||||
close(s_src);
|
||||
exit_success("no local service for %s", service);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Act as a translator
|
||||
*/
|
||||
|
||||
if (dstaddr6.__ss_family == AF_INET6) {
|
||||
if (!map6to4((struct sockaddr_in6 *)&dstaddr6,
|
||||
(struct sockaddr_in *)&dstaddr4)) {
|
||||
close(s_src);
|
||||
exit_error("map6to4 failed");
|
||||
}
|
||||
syslog(LOG_INFO, "translating from v6 to v4");
|
||||
#ifdef FAITH4
|
||||
} else if (dstaddr6.__ss_family == AF_INET) {
|
||||
if (!map4to6((struct sockaddr_in *)&dstaddr6,
|
||||
(struct sockaddr_in6 *)&dstaddr4)) {
|
||||
close(s_src);
|
||||
exit_error("map4to6 failed");
|
||||
}
|
||||
syslog(LOG_INFO, "translating from v4 to v6");
|
||||
#endif
|
||||
} else {
|
||||
close(s_src);
|
||||
exit_error("family not supported");
|
||||
}
|
||||
|
||||
getnameinfo((struct sockaddr *)&dstaddr4, dstaddr4.__ss_len,
|
||||
dst4, sizeof(dst4), NULL, 0, NI_NUMERICHOST);
|
||||
syslog(LOG_INFO, "the translator is connecting to %s", dst4);
|
||||
|
||||
setproctitle("port %s, %s -> %s", service, src, dst4);
|
||||
|
||||
if (dstaddr4.__ss_family == AF_INET6)
|
||||
hport = ntohs(((struct sockaddr_in6 *)&dstaddr4)->sin6_port);
|
||||
else /* AF_INET */
|
||||
hport = ntohs(((struct sockaddr_in *)&dstaddr4)->sin_port);
|
||||
|
||||
switch (hport) {
|
||||
case RLOGIN_PORT:
|
||||
case RSH_PORT:
|
||||
s_dst = rresvport_af(&nresvport, dstaddr4.__ss_family);
|
||||
break;
|
||||
default:
|
||||
if (pflag)
|
||||
s_dst = rresvport_af(&nresvport, dstaddr4.__ss_family);
|
||||
else
|
||||
s_dst = socket(dstaddr4.__ss_family, SOCK_STREAM, 0);
|
||||
break;
|
||||
}
|
||||
if (s_dst == -1)
|
||||
exit_failure("socket: %s", ERRSTR);
|
||||
|
||||
error = setsockopt(s_dst, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on));
|
||||
if (error == -1)
|
||||
exit_error("setsockopt: %s", ERRSTR);
|
||||
|
||||
error = setsockopt(s_src, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
|
||||
if (error == -1)
|
||||
exit_error("setsockopt: %s", ERRSTR);
|
||||
error = setsockopt(s_dst, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
|
||||
if (error == -1)
|
||||
exit_error("setsockopt: %s", ERRSTR);
|
||||
|
||||
error = connect(s_dst, (struct sockaddr *)&dstaddr4, dstaddr4.__ss_len);
|
||||
if (error == -1)
|
||||
exit_failure("connect: %s", ERRSTR);
|
||||
|
||||
switch (hport) {
|
||||
case FTP_PORT:
|
||||
ftp_relay(s_src, s_dst);
|
||||
break;
|
||||
case RSH_PORT:
|
||||
rsh_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_error("sysctl: %s", ERRSTR);
|
||||
|
||||
if (dst->sin6_addr.s6_addr32[0] == faith_prefix.s6_addr32[0]
|
||||
&& dst->sin6_addr.s6_addr32[1] == faith_prefix.s6_addr32[1]
|
||||
&& dst->sin6_addr.s6_addr32[2] == faith_prefix.s6_addr32[2])
|
||||
return 1;
|
||||
return 0;
|
||||
#else
|
||||
struct myaddrs *p;
|
||||
struct sockaddr_in6 *sin6;
|
||||
struct sockaddr_in *sin4;
|
||||
|
||||
for (p = myaddrs; p; p = p->next) {
|
||||
sin6 = (struct sockaddr_in6 *)p->addr;
|
||||
sin4 = (struct sockaddr_in *)p->addr;
|
||||
|
||||
/* ugly! */
|
||||
if (p->addr->sa_len == dst->sa_len
|
||||
&& p->addr->sa_family == dst->sa_family) {
|
||||
struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst;
|
||||
struct sockaddr_in *dst4 = (struct sockaddr_in *)dst;
|
||||
|
||||
switch (dst->sa_family) {
|
||||
case AF_INET6:
|
||||
if (sin6->sin6_scope_id == dst6->sin6_scope_id
|
||||
&& memcmp(&sin6->sin6_addr, &dst6->sin6_addr, 16) == 0)
|
||||
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;
|
||||
dst4->sin_addr.s_addr = dst6->sin6_addr.s6_addr32[3];
|
||||
|
||||
if (dst4->sin_addr.s_addr == INADDR_ANY
|
||||
|| dst4->sin_addr.s_addr == INADDR_BROADCAST
|
||||
|| IN_MULTICAST(dst4->sin_addr.s_addr))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef FAITH4
|
||||
/* 0: non faith, 1: faith */
|
||||
static int
|
||||
map4to6(struct sockaddr_in *dst4, struct sockaddr_in6 *dst6)
|
||||
{
|
||||
char host[NI_MAXHOST];
|
||||
char serv[NI_MAXSERV];
|
||||
struct addrinfo hints, *res;
|
||||
int ai_errno;
|
||||
|
||||
if (getnameinfo((struct sockaddr *)dst4, dst4->sin_len, host, sizeof(host),
|
||||
serv, sizeof(serv), NI_NAMEREQD|NI_NUMERICSERV) != 0)
|
||||
return 0;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_flags = 0;
|
||||
hints.ai_family = AF_INET6;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = 0;
|
||||
|
||||
if ((ai_errno = getaddrinfo(host, serv, &hints, &res)) != 0) {
|
||||
syslog(LOG_INFO, "%s %s: %s", host, serv, gai_strerror(ai_errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(dst6, res->ai_addr, res->ai_addrlen);
|
||||
|
||||
freeaddrinfo(res);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* FAITH4 */
|
||||
|
||||
static void
|
||||
sig_child(int sig)
|
||||
{
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
pid = wait3(&status, WNOHANG, (struct rusage *)0);
|
||||
if (pid && status)
|
||||
syslog(LOG_WARNING, "child %d exit status 0x%x", pid, status);
|
||||
}
|
||||
|
||||
void
|
||||
sig_terminate(int sig)
|
||||
{
|
||||
syslog(LOG_INFO, "Terminating faith daemon");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
start_daemon(void)
|
||||
{
|
||||
if (daemon(0, 0) == -1)
|
||||
exit_error("daemon: %s", ERRSTR);
|
||||
|
||||
if (signal(SIGCHLD, sig_child) == SIG_ERR)
|
||||
exit_failure("signal CHLD: %s", ERRSTR);
|
||||
|
||||
if (signal(SIGTERM, sig_terminate) == SIG_ERR)
|
||||
exit_failure("signal TERM: %s", ERRSTR);
|
||||
}
|
||||
|
||||
void
|
||||
exit_error(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsprintf(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);
|
||||
vsprintf(buf, fmt, ap);
|
||||
va_end(ap);
|
||||
syslog(LOG_ERR, buf);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void
|
||||
exit_success(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsprintf(buf, fmt, ap);
|
||||
va_end(ap);
|
||||
syslog(LOG_INFO, buf);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
#ifdef USE_ROUTE
|
||||
static unsigned int
|
||||
if_maxindex()
|
||||
{
|
||||
struct if_nameindex *p, *p0;
|
||||
unsigned int max = 0;
|
||||
|
||||
p0 = if_nameindex();
|
||||
for (p = p0; p && p->if_index && p->if_name; p++) {
|
||||
if (max < p->if_index)
|
||||
max = p->if_index;
|
||||
}
|
||||
if_freenameindex(p0);
|
||||
return max;
|
||||
}
|
||||
|
||||
static void
|
||||
grab_myaddrs()
|
||||
{
|
||||
int s;
|
||||
unsigned int maxif;
|
||||
struct ifreq *iflist;
|
||||
struct ifconf ifconf;
|
||||
struct ifreq *ifr, *ifr_end;
|
||||
struct myaddrs *p;
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
maxif = if_maxindex() + 1;
|
||||
iflist = (struct ifreq *)malloc(maxif * BUFSIZ); /* XXX */
|
||||
if (!iflist) {
|
||||
exit_failure("not enough core");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
exit_failure("socket(SOCK_DGRAM)");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
memset(&ifconf, 0, sizeof(ifconf));
|
||||
ifconf.ifc_req = iflist;
|
||||
ifconf.ifc_len = maxif * BUFSIZ; /* XXX */
|
||||
if (ioctl(s, SIOCGIFCONF, &ifconf) < 0) {
|
||||
exit_failure("ioctl(SIOCGIFCONF)");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
close(s);
|
||||
|
||||
/* Look for this interface in the list */
|
||||
ifr_end = (struct ifreq *) (ifconf.ifc_buf + ifconf.ifc_len);
|
||||
for (ifr = ifconf.ifc_req;
|
||||
ifr < ifr_end;
|
||||
ifr = (struct ifreq *) ((char *) &ifr->ifr_addr
|
||||
+ ifr->ifr_addr.sa_len)) {
|
||||
switch (ifr->ifr_addr.sa_family) {
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
p = (struct myaddrs *)malloc(sizeof(struct myaddrs)
|
||||
+ ifr->ifr_addr.sa_len);
|
||||
if (!p) {
|
||||
exit_failure("not enough core");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
memcpy(p + 1, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
|
||||
p->next = myaddrs;
|
||||
p->addr = (struct sockaddr *)(p + 1);
|
||||
#ifdef __KAME__
|
||||
if (ifr->ifr_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(sin6->sin6_addr.s6_addr16[1]);
|
||||
sin6->sin6_addr.s6_addr16[1] = 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, ifr->ifr_name);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(iflist);
|
||||
}
|
||||
|
||||
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) {
|
||||
syslog(LOG_ERR, "routing socket version mismatch");
|
||||
close(sockfd);
|
||||
sockfd = 0;
|
||||
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] [service [serverpath [serverargs]]]\n",
|
||||
faithdname);
|
||||
exit(0);
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/* $NetBSD: faithd.h,v 1.1 1999/07/13 22:16:49 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 __P((int, int, const char *));
|
||||
extern void ftp_relay __P((int, int));
|
||||
extern int ftp_active __P((int, int, int *, int *));
|
||||
extern int ftp_passive __P((int, int, int *, int *));
|
||||
extern void rsh_relay __P((int, int));
|
||||
extern void rsh_dual_relay __P((int, int));
|
||||
extern void exit_error __P((const char *fmt, ...));
|
||||
extern void exit_success __P((const char *fmt, ...));
|
||||
extern void exit_failure __P((const char *fmt, ...));
|
||||
|
||||
#define DEFAULT_PORT_NAME "telnet"
|
||||
#define DEFAULT_PATH "/usr/local/v6/libexec/telnetd"
|
||||
#define DEFAULT_NAME "telnetd"
|
||||
|
||||
#define FTP_PORT 21
|
||||
#define RLOGIN_PORT 513
|
||||
#define RSH_PORT 514
|
||||
|
||||
#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 ERRSTR strerror(errno)
|
||||
|
||||
#define FAITH_TIMEOUT (30 * 60) /*second*/
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,208 @@
|
|||
/* $NetBSD: rsh.c,v 1.1 1999/07/13 22:16:49 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 <errno.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "faithd.h"
|
||||
|
||||
char rshbuf[MSS];
|
||||
|
||||
int s_ctl, s_ctl6, s_rcv, s_snd;
|
||||
int half;
|
||||
|
||||
void
|
||||
rsh_relay(int s_src, int s_dst)
|
||||
{
|
||||
ssize_t n;
|
||||
fd_set readfds;
|
||||
int error;
|
||||
struct timeval tv;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(s_src, &readfds);
|
||||
tv.tv_sec = FAITH_TIMEOUT;
|
||||
tv.tv_usec = 0;
|
||||
error = select(256, &readfds, NULL, NULL, &tv);
|
||||
if (error == -1)
|
||||
exit_failure("select %d: %s", s_src, ERRSTR);
|
||||
else if (error == 0)
|
||||
exit_failure("connecion timeout");
|
||||
|
||||
n = read(s_src, rshbuf, sizeof(rshbuf));
|
||||
if (rshbuf[0] != 0) {
|
||||
rsh_dual_relay(s_src, s_dst);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
write(s_dst, rshbuf, n);
|
||||
tcp_relay(s_src, s_dst, "rsh");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static void
|
||||
relay(int src, int dst)
|
||||
{
|
||||
int error;
|
||||
ssize_t n;
|
||||
int atmark;
|
||||
|
||||
error = ioctl(s_rcv, SIOCATMARK, &atmark);
|
||||
if (error != -1 && atmark == 1) {
|
||||
n = read(s_rcv, rshbuf, 1);
|
||||
if (n == 1)
|
||||
send(s_snd, rshbuf, 1, MSG_OOB);
|
||||
return;
|
||||
}
|
||||
|
||||
n = read(s_rcv, rshbuf, sizeof(rshbuf));
|
||||
|
||||
switch (n) {
|
||||
case -1:
|
||||
exit_failure(ERRSTR);
|
||||
case 0:
|
||||
if (s_rcv == src) {
|
||||
/* half close */
|
||||
shutdown(dst, 1);
|
||||
half = YES;
|
||||
break;
|
||||
}
|
||||
close(src);
|
||||
close(dst);
|
||||
close(s_ctl);
|
||||
close(s_ctl6);
|
||||
exit_success("terminating rsh/contorol connections");
|
||||
break;
|
||||
default:
|
||||
write(s_snd, rshbuf, n);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rsh_dual_relay(int s_src, int s_dst)
|
||||
{
|
||||
fd_set readfds;
|
||||
int len, s_wld, error;
|
||||
struct sockaddr_storage ctladdr6;
|
||||
struct sockaddr_storage ctladdr;
|
||||
int port6 = 0, lport, lport6;
|
||||
char *p;
|
||||
struct timeval tv;
|
||||
|
||||
half = NO;
|
||||
s_rcv = s_src;
|
||||
s_snd = s_dst;
|
||||
syslog(LOG_INFO, "starting rsh connection");
|
||||
|
||||
for (p = rshbuf; *p; p++)
|
||||
port6 = port6 * 10 + *p - '0';
|
||||
|
||||
len = sizeof(ctladdr6);
|
||||
getpeername(s_src, (struct sockaddr *)&ctladdr6, &len);
|
||||
if (ctladdr6.__ss_family == AF_INET6)
|
||||
((struct sockaddr_in6 *)&ctladdr6)->sin6_port = htons(port6);
|
||||
else
|
||||
((struct sockaddr_in *)&ctladdr6)->sin_port = htons(port6);
|
||||
|
||||
s_wld = rresvport(&lport);
|
||||
if (s_wld == -1) goto bad;
|
||||
error = listen(s_wld, 1);
|
||||
if (error == -1) goto bad;
|
||||
snprintf(rshbuf, sizeof(rshbuf), "%d", lport);
|
||||
write(s_dst, rshbuf, strlen(rshbuf)+1);
|
||||
|
||||
len = sizeof(ctladdr);
|
||||
s_ctl = accept(s_wld, (struct sockaddr *)&ctladdr, &len);
|
||||
if (s_ctl == -1) goto bad;
|
||||
close(s_wld);
|
||||
|
||||
s_ctl6 = rresvport_af(&lport6, ctladdr6.__ss_family);
|
||||
if (s_ctl6 == -1) goto bad;
|
||||
error = connect(s_ctl6, (struct sockaddr *)&ctladdr6, ctladdr6.__ss_len);
|
||||
if (error == -1) goto bad;
|
||||
|
||||
syslog(LOG_INFO, "starting rsh control connection");
|
||||
|
||||
for (;;) {
|
||||
FD_ZERO(&readfds);
|
||||
if (half == NO)
|
||||
FD_SET(s_src, &readfds);
|
||||
FD_SET(s_dst, &readfds);
|
||||
FD_SET(s_ctl, &readfds);
|
||||
FD_SET(s_ctl6, &readfds);
|
||||
tv.tv_sec = FAITH_TIMEOUT;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
error = select(256, &readfds, NULL, NULL, &tv);
|
||||
if (error == -1)
|
||||
exit_failure("select 4 sockets: %s", ERRSTR);
|
||||
else if (error == 0)
|
||||
exit_failure("connecion timeout");
|
||||
|
||||
if (half == NO && FD_ISSET(s_src, &readfds)) {
|
||||
s_rcv = s_src;
|
||||
s_snd = s_dst;
|
||||
relay(s_src, s_dst);
|
||||
}
|
||||
if (FD_ISSET(s_dst, &readfds)) {
|
||||
s_rcv = s_dst;
|
||||
s_snd = s_src;
|
||||
relay(s_src, s_dst);
|
||||
}
|
||||
if (FD_ISSET(s_ctl, &readfds)) {
|
||||
s_rcv = s_ctl;
|
||||
s_snd = s_ctl6;
|
||||
relay(s_src, s_dst);
|
||||
}
|
||||
if (FD_ISSET(s_ctl6, &readfds)) {
|
||||
s_rcv = s_ctl6;
|
||||
s_snd = s_ctl;
|
||||
relay(s_src, s_dst);
|
||||
}
|
||||
}
|
||||
/* NOTREACHED */
|
||||
|
||||
bad:
|
||||
exit_failure(ERRSTR);
|
||||
}
|
|
@ -0,0 +1,300 @@
|
|||
/* $NetBSD: tcp.c,v 1.1 1999/07/13 22:16:49 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;
|
||||
static time_t child_lastactive = (time_t)0;
|
||||
static time_t parent_lastactive = (time_t)0;
|
||||
|
||||
static void sig_ctimeout __P((int));
|
||||
static void sig_child __P((int));
|
||||
static void notify_inactive __P((void));
|
||||
static void notify_active __P((void));
|
||||
static void send_data __P((int, int, const char *, int));
|
||||
static void relay __P((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)
|
||||
{
|
||||
/* parent side: record notification from the child */
|
||||
if (dflag)
|
||||
syslog(LOG_DEBUG, "activity timer from child");
|
||||
child_lastactive = time(NULL);
|
||||
}
|
||||
|
||||
/* parent will terminate if child dies. */
|
||||
static void
|
||||
sig_child(int sig)
|
||||
{
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
pid = wait3(&status, WNOHANG, (struct rusage *)0);
|
||||
if (pid && status)
|
||||
syslog(LOG_WARNING, "child %d exit status 0x%x", pid, status);
|
||||
exit_failure("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;
|
||||
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;
|
||||
FD_CLR(s_snd, &writefds);
|
||||
FD_SET(s_rcv, &readfds);
|
||||
return;
|
||||
retry_or_err:
|
||||
if (errno != EAGAIN)
|
||||
exit_failure("writing relay data failed: %s", ERRSTR);
|
||||
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;
|
||||
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", ERRSTR);
|
||||
} 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) {
|
||||
FD_CLR(s_rcv, &exceptfds);
|
||||
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",
|
||||
ERRSTR);
|
||||
}
|
||||
}
|
||||
}
|
||||
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",
|
||||
ERRSTR);
|
||||
/* 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:
|
||||
FD_CLR(s_rcv, &readfds);
|
||||
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", ERRSTR);
|
||||
/* 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 */
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue