- poll(2) support.
- simplify by strdup. - set ai_protocol in hints to TCP. - g/c FAITH_NS (no description, not maintained for years) - warn if connection from IPv4 mapped is reached. - IPV6_V6ONLY if possible. - unifdef -UFAITH4. - drop rsh/rlogin support. - deal with negative return value from wait3. Obtained from: KAME
This commit is contained in:
parent
b0479caf61
commit
1cc5ee037b
@ -16,8 +16,8 @@
|
||||
|
||||
PROG= faithd
|
||||
MAN= faithd.8
|
||||
SRCS= faithd.c tcp.c ftp.c rsh.c prefix.c
|
||||
SRCS= faithd.c tcp.c ftp.c prefix.c
|
||||
|
||||
#CFLAGS+= -DFAITH4
|
||||
CFLAGS= -DHAVE_POLL_H
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -1,9 +1,10 @@
|
||||
Configuring FAITH IPv6-to-IPv4 TCP relay
|
||||
|
||||
Kazu Yamamoto and Jun-ichiro itojun Hagino
|
||||
$KAME: README,v 1.8 2001/09/05 03:04:20 itojun Exp $
|
||||
$KAME: README,v 1.10 2003/01/06 21:40:33 sumikawa Exp $
|
||||
$FreeBSD$
|
||||
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
@ -73,8 +74,6 @@ The following example assumes:
|
||||
|
||||
More examples:
|
||||
|
||||
# faithd login /usr/libexec/rlogin rlogind
|
||||
# faithd shell /usr/libexec/rshd rshd
|
||||
# faithd ftpd /usr/libexec/ftpd ftpd -l
|
||||
# faithd sshd
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $KAME: faithd.8,v 1.33 2001/09/05 03:04:20 itojun Exp $
|
||||
.\" $KAME: faithd.8,v 1.37 2002/05/09 14:21:23 itojun Exp $
|
||||
.\"
|
||||
.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
.\" All rights reserved.
|
||||
@ -41,10 +41,12 @@
|
||||
.Op Fl f Ar configfile
|
||||
.Ar service
|
||||
.Op Ar serverpath Op Ar serverargs
|
||||
.Nm ""
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility provides IPv6-to-IPv4 TCP relay. It
|
||||
utility provides IPv6-to-IPv4 TCP relay.
|
||||
.Nm
|
||||
must be used on an IPv4/v6 dual stack router.
|
||||
.Pp
|
||||
When
|
||||
@ -65,7 +67,7 @@ destination.
|
||||
For example, if
|
||||
.Li 3ffe:0501:4819:ffff::
|
||||
is reserved for
|
||||
.Nm ,
|
||||
.Nm Ns ,
|
||||
and the
|
||||
.Tn TCPv6
|
||||
destination address is
|
||||
@ -116,7 +118,6 @@ at
|
||||
.Pa http://www.vermicelli.pasta.cs.uit.no/ipv6/software.html .
|
||||
Make sure you do not propagate translated DNS records to normal DNS cloud,
|
||||
it is highly harmful.
|
||||
.Pp
|
||||
.Ss Daemon mode
|
||||
When
|
||||
.Nm
|
||||
@ -147,7 +148,7 @@ or other standard mechanisms.
|
||||
By specifying
|
||||
.Ar serverpath
|
||||
to
|
||||
.Nm ,
|
||||
.Nm Ns ,
|
||||
you can run local daemons on the router.
|
||||
The
|
||||
.Nm
|
||||
@ -172,8 +173,6 @@ Use privileged TCP port number as source port,
|
||||
for IPv4 TCP connection toward final destination.
|
||||
For relaying
|
||||
.Xr ftp 1
|
||||
and
|
||||
.Xr rlogin 1 ,
|
||||
this flag is not necessary as special program code is supplied.
|
||||
.El
|
||||
.Pp
|
||||
@ -184,9 +183,7 @@ It is capable of emulating TCP half close as well.
|
||||
The
|
||||
.Nm
|
||||
utility includes special support for protocols used by
|
||||
.Xr ftp 1
|
||||
and
|
||||
.Xr rlogin 1 .
|
||||
.Xr ftp 1 .
|
||||
When translating FTP protocol,
|
||||
.Nm
|
||||
translates network level addresses in
|
||||
@ -194,18 +191,11 @@ translates network level addresses in
|
||||
and
|
||||
.Li PASV/LPSV/EPSV
|
||||
commands.
|
||||
For RLOGIN protocol,
|
||||
.Nm
|
||||
will relay back connection from
|
||||
.Xr rlogind 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
|
||||
(should this be configurable?).
|
||||
.Pq should this be configurable? .
|
||||
.Ss inetd mode
|
||||
When
|
||||
.Nm
|
||||
@ -243,10 +233,12 @@ To prevent malicious accesses,
|
||||
implements a simple address-based access control.
|
||||
With
|
||||
.Pa /etc/faithd.conf
|
||||
(or
|
||||
.Po
|
||||
or
|
||||
.Ar configfile
|
||||
specified by
|
||||
.Fl f ) ,
|
||||
.Fl f
|
||||
.Pc ,
|
||||
.Nm
|
||||
will avoid relaying unwanted traffic.
|
||||
The
|
||||
@ -254,35 +246,48 @@ The
|
||||
contains directives with the following format:
|
||||
.Bl -bullet
|
||||
.It
|
||||
.Ar src Ns / Ns Ar slen Cm deny Ar dst Ns / Ns Ar dlen
|
||||
.Xo
|
||||
.Ic Ar src/slen Li deny Ar dst/dlen
|
||||
.Xc
|
||||
.Pp
|
||||
If the source address of a query matches
|
||||
.Ar src Ns / Ns Ar slen ,
|
||||
.Ar src/slen ,
|
||||
and the translated destination address matches
|
||||
.Ar dst Ns / Ns Ar dlen ,
|
||||
.Ar dst/dlen ,
|
||||
deny the connection.
|
||||
.It
|
||||
.Ar src Ns / Ns Ar slen Cm permit Ar dst Ns / Ns Ar dlen
|
||||
.Xo
|
||||
.Ic Ar src/slen Li permit Ar dst/dlen
|
||||
.Xc
|
||||
.Pp
|
||||
If the source address of a query matches
|
||||
.Ar src Ns / Ns Ar slen ,
|
||||
.Ar src/slen ,
|
||||
and the translated destination address matches
|
||||
.Ar dst Ns / Ns Ar dlen ,
|
||||
.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
|
||||
(if we reach the end of the ruleset)
|
||||
.Pq if we reach the end of the ruleset
|
||||
the traffic will be 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 ,
|
||||
.Nm Ns ,
|
||||
.Xr faith 4
|
||||
interface has to be configured properly.
|
||||
.Bd -literal -offset
|
||||
@ -320,26 +325,19 @@ If you would like to pass extra arguments to the local daemon:
|
||||
Here are some other examples.
|
||||
You may need
|
||||
.Fl p
|
||||
to translate rsh/rlogin services.
|
||||
if the service checks the source port range.
|
||||
.Bd -literal -offset
|
||||
# faithd ssh
|
||||
# faithd login /usr/libexec/rlogin rlogind
|
||||
# faithd shell /usr/libexec/rshd rshd
|
||||
# faithd telnet /usr/libexec/telnetd telnetd
|
||||
.Ed
|
||||
.Pp
|
||||
However, you should be careful when translating rlogin or rsh
|
||||
connections.
|
||||
See
|
||||
.Sx SECURITY CONSIDERATIONS
|
||||
for more details.
|
||||
.Ss inetd mode samples
|
||||
Add the following lines into
|
||||
.Xr inetd.conf 5 .
|
||||
Syntax may vary depending upon your operating system.
|
||||
.Bd -literal -offset
|
||||
telnet stream tcp6/faith nowait root /usr/sbin/faithd telnetd
|
||||
ftp stream tcp6/faith nowait root /usr/sbin/faithd ftpd -l
|
||||
ssh stream tcp6/faith nowait root /usr/sbin/faithd /usr/sbin/sshd -i
|
||||
telnet stream tcp6/faith nowait root faithd telnetd
|
||||
ftp stream tcp6/faith nowait root faithd ftpd -l
|
||||
ssh stream tcp6/faith nowait root faithd /usr/sbin/sshd -i
|
||||
.Ed
|
||||
.Pp
|
||||
.Xr inetd 8
|
||||
@ -370,16 +368,6 @@ setting.
|
||||
3ffe:501:ffff::/48 deny 127.0.0.0/8
|
||||
3ffe:501:ffff::/48 permit 0.0.0.0/0
|
||||
.Ed
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Nm
|
||||
utility exits with
|
||||
.Dv EXIT_SUCCESS
|
||||
.Pq 0
|
||||
on success, and
|
||||
.Dv EXIT_FAILURE
|
||||
.Pq 1
|
||||
on error.
|
||||
.Sh SEE ALSO
|
||||
.Xr faith 4 ,
|
||||
.Xr route 8 ,
|
||||
@ -403,11 +391,9 @@ IPv6 and IPsec support based on the KAME Project (http://www.kame.net/) stack
|
||||
was initially integrated into
|
||||
.Fx 4.0
|
||||
.Sh SECURITY CONSIDERATIONS
|
||||
It is very insecure to use
|
||||
.Xr rhosts 5
|
||||
and other IP-address based authentication, for connections relayed by
|
||||
.Nm
|
||||
(and any other TCP relaying services).
|
||||
It is very insecure to use IP-address based authentication, for connections relayed by
|
||||
.Nm Ns ,
|
||||
and any other TCP relaying services.
|
||||
.Pp
|
||||
Administrators are advised to limit accesses to
|
||||
.Nm
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $KAME: faithd.c,v 1.46 2002/01/24 16:40:42 sumikawa Exp $ */
|
||||
/* $KAME: faithd.c,v 1.67 2003/10/16 05:26:21 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1997 and 1998 WIDE Project.
|
||||
@ -46,10 +46,11 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef __FreeBSD__
|
||||
#include <libutil.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POLL_H
|
||||
#include <poll.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
@ -74,14 +75,6 @@
|
||||
#include <netdb.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#ifdef FAITH4
|
||||
#include <resolv.h>
|
||||
#include <arpa/nameser.h>
|
||||
#ifndef FAITH_NS
|
||||
#define FAITH_NS "FAITH_NS"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "faithd.h"
|
||||
#include "prefix.h"
|
||||
|
||||
@ -90,11 +83,13 @@ 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;
|
||||
@ -111,9 +106,6 @@ 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));
|
||||
@ -151,7 +143,7 @@ inetd_main(int argc, char **argv)
|
||||
char path[MAXPATHLEN];
|
||||
struct sockaddr_storage me;
|
||||
struct sockaddr_storage from;
|
||||
int melen, fromlen;
|
||||
socklen_t melen, fromlen;
|
||||
int i;
|
||||
int error;
|
||||
const int on = 1;
|
||||
@ -228,11 +220,8 @@ daemon_main(int argc, char **argv)
|
||||
int s_wld, error, i, serverargc, on = 1;
|
||||
int family = AF_INET6;
|
||||
int c;
|
||||
#ifdef FAITH_NS
|
||||
char *ns;
|
||||
#endif /* FAITH_NS */
|
||||
|
||||
while ((c = getopt(argc, argv, "df:p46")) != -1) {
|
||||
while ((c = getopt(argc, argv, "df:p")) != -1) {
|
||||
switch (c) {
|
||||
case 'd':
|
||||
dflag++;
|
||||
@ -243,14 +232,6 @@ daemon_main(int argc, char **argv)
|
||||
case 'p':
|
||||
pflag++;
|
||||
break;
|
||||
#ifdef FAITH4
|
||||
case '4':
|
||||
family = AF_INET;
|
||||
break;
|
||||
case '6':
|
||||
family = AF_INET6;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
usage();
|
||||
/*NOTREACHED*/
|
||||
@ -264,23 +245,6 @@ daemon_main(int argc, char **argv)
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
#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));
|
||||
snprintf(serv, sizeof(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();
|
||||
@ -295,11 +259,13 @@ daemon_main(int argc, char **argv)
|
||||
if (serverargc >= MAXARGV)
|
||||
exit_stderr("too many arguments");
|
||||
|
||||
serverpath = malloc(strlen(argv[NUMPRG]) + 1);
|
||||
strcpy(serverpath, argv[NUMPRG]);
|
||||
serverpath = strdup(argv[NUMPRG]);
|
||||
if (!serverpath)
|
||||
exit_stderr("not enough core");
|
||||
for (i = 0; i < serverargc; i++) {
|
||||
serverarg[i] = malloc(strlen(argv[i + NUMARG]) + 1);
|
||||
strcpy(serverarg[i], argv[i + NUMARG]);
|
||||
serverarg[i] = strdup(argv[i + NUMARG]);
|
||||
if (!serverarg[i])
|
||||
exit_stderr("not enough core");
|
||||
}
|
||||
serverarg[i] = NULL;
|
||||
/* fall throuth */
|
||||
@ -308,6 +274,8 @@ daemon_main(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
|
||||
start_daemon();
|
||||
|
||||
/*
|
||||
* Opening wild card socket for this service.
|
||||
*/
|
||||
@ -316,7 +284,7 @@ daemon_main(int argc, char **argv)
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
hints.ai_family = family;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = 0;
|
||||
hints.ai_protocol = IPPROTO_TCP; /* SCTP? */
|
||||
error = getaddrinfo(NULL, service, &hints, &res);
|
||||
if (error)
|
||||
exit_failure("getaddrinfo: %s", gai_strerror(error));
|
||||
@ -333,16 +301,6 @@ daemon_main(int argc, char **argv)
|
||||
strerror(errno));
|
||||
}
|
||||
#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_failure("setsockopt(IP_FAITH): %s",
|
||||
strerror(errno));
|
||||
}
|
||||
#endif
|
||||
#endif /* FAITH4 */
|
||||
|
||||
error = setsockopt(s_wld, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||
if (error == -1)
|
||||
@ -352,6 +310,12 @@ daemon_main(int argc, char **argv)
|
||||
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));
|
||||
@ -372,8 +336,6 @@ daemon_main(int argc, char **argv)
|
||||
* Everything is OK.
|
||||
*/
|
||||
|
||||
start_daemon();
|
||||
|
||||
snprintf(logname, sizeof(logname), "faithd %s", service);
|
||||
snprintf(procname, sizeof(procname), "accepting port %s", service);
|
||||
openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
|
||||
@ -388,12 +350,16 @@ static void
|
||||
play_service(int s_wld)
|
||||
{
|
||||
struct sockaddr_storage srcaddr;
|
||||
int len;
|
||||
socklen_t len;
|
||||
int s_src;
|
||||
pid_t child_pid;
|
||||
#ifdef HAVE_POLL_H
|
||||
struct pollfd pfd[2];
|
||||
#else
|
||||
fd_set rfds;
|
||||
int error;
|
||||
int maxfd;
|
||||
#endif
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Wait, accept, fork, faith....
|
||||
@ -401,17 +367,37 @@ play_service(int s_wld)
|
||||
again:
|
||||
setproctitle("%s", procname);
|
||||
|
||||
#ifdef HAVE_POLL_H
|
||||
pfd[0].fd = s_wld;
|
||||
pfd[0].events = POLLIN;
|
||||
pfd[1].fd = -1;
|
||||
pfd[1].revents = 0;
|
||||
#else
|
||||
FD_ZERO(&rfds);
|
||||
if (s_wld >= FD_SETSIZE)
|
||||
exit_failure("descriptor too big");
|
||||
FD_SET(s_wld, &rfds);
|
||||
maxfd = s_wld;
|
||||
#endif
|
||||
#ifdef USE_ROUTE
|
||||
if (sockfd) {
|
||||
#ifdef HAVE_POLL_H
|
||||
pfd[1].fd = sockfd;
|
||||
pfd[1].events = POLLIN;
|
||||
#else
|
||||
if (sockfd >= FD_SETSIZE)
|
||||
exit_failure("descriptor too big");
|
||||
FD_SET(sockfd, &rfds);
|
||||
maxfd = (maxfd < sockfd) ? sockfd : maxfd;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POLL_H
|
||||
error = poll(pfd, sizeof(pfd)/sizeof(pfd[0]), INFTIM);
|
||||
#else
|
||||
error = select(maxfd + 1, &rfds, NULL, NULL, NULL);
|
||||
#endif
|
||||
if (error < 0) {
|
||||
if (errno == EINTR)
|
||||
goto again;
|
||||
@ -420,23 +406,38 @@ play_service(int s_wld)
|
||||
}
|
||||
|
||||
#ifdef USE_ROUTE
|
||||
if (FD_ISSET(sockfd, &rfds)) {
|
||||
#ifdef HAVE_POLL_H
|
||||
if (pfd[1].revents & POLLIN)
|
||||
#else
|
||||
if (FD_ISSET(sockfd, &rfds))
|
||||
#endif
|
||||
{
|
||||
update_myaddrs();
|
||||
}
|
||||
#endif
|
||||
if (FD_ISSET(s_wld, &rfds)) {
|
||||
#ifdef HAVE_POLL_H
|
||||
if (pfd[0].revents & POLLIN)
|
||||
#else
|
||||
if (FD_ISSET(s_wld, &rfds))
|
||||
#endif
|
||||
{
|
||||
len = sizeof(srcaddr);
|
||||
s_src = accept(s_wld, (struct sockaddr *)&srcaddr,
|
||||
&len);
|
||||
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);
|
||||
@ -463,7 +464,7 @@ play_child(int s_src, struct sockaddr *srcaddr)
|
||||
char src[NI_MAXHOST];
|
||||
char dst6[NI_MAXHOST];
|
||||
char dst4[NI_MAXHOST];
|
||||
int len = sizeof(dstaddr6);
|
||||
socklen_t len = sizeof(dstaddr6);
|
||||
int s_dst, error, hport, nresvport, on = 1;
|
||||
struct timeval tv;
|
||||
struct sockaddr *sa4;
|
||||
@ -473,7 +474,7 @@ play_child(int s_src, struct sockaddr *srcaddr)
|
||||
tv.tv_usec = 0;
|
||||
|
||||
getnameinfo(srcaddr, srcaddr->sa_len,
|
||||
src, sizeof(src), NULL, 0, NI_NUMERICHOST);
|
||||
src, sizeof(src), NULL, 0, NI_NUMERICHOST);
|
||||
syslog(LOG_INFO, "accepted a client from %s", src);
|
||||
|
||||
error = getsockname(s_src, (struct sockaddr *)&dstaddr6, &len);
|
||||
@ -483,7 +484,7 @@ play_child(int s_src, struct sockaddr *srcaddr)
|
||||
}
|
||||
|
||||
getnameinfo((struct sockaddr *)&dstaddr6, len,
|
||||
dst6, sizeof(dst6), NULL, 0, NI_NUMERICHOST);
|
||||
dst6, sizeof(dst6), NULL, 0, NI_NUMERICHOST);
|
||||
syslog(LOG_INFO, "the client is connecting to %s", dst6);
|
||||
|
||||
if (!faith_prefix((struct sockaddr *)&dstaddr6)) {
|
||||
@ -522,17 +523,6 @@ play_child(int s_src, struct sockaddr *srcaddr)
|
||||
}
|
||||
syslog(LOG_INFO, "translating from v6 to v4");
|
||||
break;
|
||||
#ifdef FAITH4
|
||||
case AF_INET:
|
||||
if (!map4to6((struct sockaddr_in *)&dstaddr6,
|
||||
(struct sockaddr_in6 *)&dstaddr4)) {
|
||||
close(s_src);
|
||||
exit_failure("map4to6 failed");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
syslog(LOG_INFO, "translating from v4 to v6");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
close(s_src);
|
||||
exit_failure("family not supported");
|
||||
@ -541,7 +531,7 @@ play_child(int s_src, struct sockaddr *srcaddr)
|
||||
|
||||
sa4 = (struct sockaddr *)&dstaddr4;
|
||||
getnameinfo(sa4, sa4->sa_len,
|
||||
dst4, sizeof(dst4), NULL, 0, NI_NUMERICHOST);
|
||||
dst4, sizeof(dst4), NULL, 0, NI_NUMERICHOST);
|
||||
|
||||
conf = config_match(srcaddr, sa4);
|
||||
if (!conf || !conf->permit) {
|
||||
@ -565,18 +555,10 @@ play_child(int s_src, struct sockaddr *srcaddr)
|
||||
else /* AF_INET */
|
||||
hport = ntohs(((struct sockaddr_in *)&dstaddr4)->sin_port);
|
||||
|
||||
switch (hport) {
|
||||
case RLOGIN_PORT:
|
||||
case RSH_PORT:
|
||||
if (pflag)
|
||||
s_dst = rresvport_af(&nresvport, sa4->sa_family);
|
||||
break;
|
||||
default:
|
||||
if (pflag)
|
||||
s_dst = rresvport_af(&nresvport, sa4->sa_family);
|
||||
else
|
||||
s_dst = socket(sa4->sa_family, SOCK_STREAM, 0);
|
||||
break;
|
||||
}
|
||||
else
|
||||
s_dst = socket(sa4->sa_family, SOCK_STREAM, 0);
|
||||
if (s_dst < 0) {
|
||||
exit_failure("socket: %s", strerror(errno));
|
||||
/*NOTREACHED*/
|
||||
@ -617,15 +599,6 @@ play_child(int s_src, struct sockaddr *srcaddr)
|
||||
case FTP_PORT:
|
||||
ftp_relay(s_src, s_dst);
|
||||
break;
|
||||
case RSH_PORT:
|
||||
syslog(LOG_WARNING,
|
||||
"WARINNG: it is insecure to relay rsh port");
|
||||
rsh_relay(s_src, s_dst);
|
||||
break;
|
||||
case RLOGIN_PORT:
|
||||
syslog(LOG_WARNING,
|
||||
"WARINNG: it is insecure to relay rlogin port");
|
||||
/*FALLTHROUGH*/
|
||||
default:
|
||||
tcp_relay(s_src, s_dst, service);
|
||||
break;
|
||||
@ -657,7 +630,7 @@ faith_prefix(struct sockaddr *dst)
|
||||
}
|
||||
|
||||
if (memcmp(dst, &faith_prefix,
|
||||
sizeof(struct in6_addr) - sizeof(struct in_addr) == 0) {
|
||||
sizeof(struct in6_addr) - sizeof(struct in_addr) == 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -727,39 +700,6 @@ map6to4(struct sockaddr_in6 *dst6, struct sockaddr_in *dst4)
|
||||
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)
|
||||
@ -767,9 +707,10 @@ sig_child(int sig)
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
pid = wait3(&status, WNOHANG, (struct rusage *)0);
|
||||
if (pid && WEXITSTATUS(status))
|
||||
syslog(LOG_WARNING, "child %d exit status 0x%x", pid, status);
|
||||
while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0)
|
||||
if (WEXITSTATUS(status))
|
||||
syslog(LOG_WARNING, "child %ld exit status 0x%x",
|
||||
(long)pid, status);
|
||||
}
|
||||
|
||||
void
|
||||
@ -894,8 +835,8 @@ grab_myaddrs()
|
||||
if (dflag) {
|
||||
char hbuf[NI_MAXHOST];
|
||||
getnameinfo(p->addr, p->addr->sa_len,
|
||||
hbuf, sizeof(hbuf), NULL, 0,
|
||||
NI_NUMERICHOST);
|
||||
hbuf, sizeof(hbuf), NULL, 0,
|
||||
NI_NUMERICHOST);
|
||||
syslog(LOG_INFO, "my interface: %s %s", hbuf,
|
||||
ifa->ifa_name);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $KAME: faithd.h,v 1.8 2001/09/05 03:04:21 itojun Exp $ */
|
||||
/* $KAME: faithd.h,v 1.9 2002/05/09 09:41:24 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1997 and 1998 WIDE Project.
|
||||
@ -38,8 +38,6 @@ 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_success __P((const char *, ...))
|
||||
__attribute__((__format__(__printf__, 1, 2)));
|
||||
extern void exit_failure __P((const char *, ...))
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $KAME: ftp.c,v 1.11 2001/07/02 14:36:49 itojun Exp $ */
|
||||
/* $KAME: ftp.c,v 1.23 2003/08/19 21:20:33 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1997 and 1998 WIDE Project.
|
||||
@ -42,6 +42,9 @@
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_POLL_H
|
||||
#include <poll.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
@ -62,11 +65,7 @@ static struct sockaddr_storage data4; /* server data address */
|
||||
static struct sockaddr_storage data6; /* client data address */
|
||||
static int epsvall = 0;
|
||||
|
||||
#ifdef FAITH4
|
||||
enum state { NONE, LPRT, EPRT, PORT, LPSV, EPSV, PASV };
|
||||
#else
|
||||
enum state { NONE, LPRT, EPRT, LPSV, EPSV };
|
||||
#endif
|
||||
|
||||
static int ftp_activeconn __P((void));
|
||||
static int ftp_passiveconn __P((void));
|
||||
@ -77,7 +76,11 @@ static int ftp_copycommand __P((int, int, enum state *));
|
||||
void
|
||||
ftp_relay(int ctl6, int ctl4)
|
||||
{
|
||||
#ifdef HAVE_POLL_H
|
||||
struct pollfd pfd[6];
|
||||
#else
|
||||
fd_set readfds;
|
||||
#endif
|
||||
int error;
|
||||
enum state state = NONE;
|
||||
struct timeval tv;
|
||||
@ -85,25 +88,90 @@ ftp_relay(int ctl6, int ctl4)
|
||||
syslog(LOG_INFO, "starting ftp control connection");
|
||||
|
||||
for (;;) {
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(ctl4, &readfds);
|
||||
FD_SET(ctl6, &readfds);
|
||||
if (0 <= port4)
|
||||
FD_SET(port4, &readfds);
|
||||
if (0 <= port6)
|
||||
FD_SET(port6, &readfds);
|
||||
#ifdef HAVE_POLL_H
|
||||
pfd[0].fd = ctl4;
|
||||
pfd[0].events = POLLIN;
|
||||
pfd[1].fd = ctl6;
|
||||
pfd[1].events = POLLIN;
|
||||
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)
|
||||
if (0 <= wport4) {
|
||||
pfd[4].fd = wport4;
|
||||
pfd[4].events = POLLIN;
|
||||
} else
|
||||
pfd[4].fd = -1;
|
||||
if (0 <= wport6) {
|
||||
pfd[5].fd = wport4;
|
||||
pfd[5].events = POLLIN;
|
||||
} else
|
||||
pfd[5].fd = -1;
|
||||
#else
|
||||
pfd[4].fd = pfd[5].fd = -1;
|
||||
pfd[4].events = pfd[5].events = 0;
|
||||
#endif
|
||||
#else
|
||||
int maxfd = 0;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
if (ctl4 >= FD_SETSIZE)
|
||||
exit_failure("descriptor too big");
|
||||
FD_SET(ctl4, &readfds);
|
||||
maxfd = ctl4;
|
||||
if (ctl6 >= FD_SETSIZE)
|
||||
exit_failure("descriptor too big");
|
||||
FD_SET(ctl6, &readfds);
|
||||
maxfd = (ctl6 > maxfd) ? ctl6 : maxfd;
|
||||
if (0 <= port4) {
|
||||
if (port4 >= FD_SETSIZE)
|
||||
exit_failure("descriptor too big");
|
||||
FD_SET(port4, &readfds);
|
||||
maxfd = (port4 > maxfd) ? port4 : maxfd;
|
||||
}
|
||||
if (0 <= port6) {
|
||||
if (port6 >= FD_SETSIZE)
|
||||
exit_failure("descriptor too big");
|
||||
FD_SET(port6, &readfds);
|
||||
maxfd = (port6 > maxfd) ? port6 : maxfd;
|
||||
}
|
||||
#if 0
|
||||
if (0 <= wport4) {
|
||||
if (wport4 >= FD_SETSIZE)
|
||||
exit_failure("descriptor too big");
|
||||
FD_SET(wport4, &readfds);
|
||||
if (0 <= wport6)
|
||||
maxfd = (wport4 > maxfd) ? wport4 : maxfd;
|
||||
}
|
||||
if (0 <= wport6) {
|
||||
if (wport6 >= FD_SETSIZE)
|
||||
exit_failure("descriptor too big");
|
||||
FD_SET(wport6, &readfds);
|
||||
maxfd = (wport6 > maxfd) ? wport6 : maxfd;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
tv.tv_sec = FAITH_TIMEOUT;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
error = select(256, &readfds, NULL, NULL, &tv);
|
||||
if (error == -1)
|
||||
#ifdef HAVE_POLL_H
|
||||
error = poll(pfd, sizeof(pfd)/sizeof(pfd[0]), tv.tv_sec * 1000);
|
||||
#else
|
||||
error = select(maxfd + 1, &readfds, NULL, NULL, &tv);
|
||||
#endif
|
||||
if (error == -1) {
|
||||
#ifdef HAVE_POLL_H
|
||||
exit_failure("poll: %s", strerror(errno));
|
||||
#else
|
||||
exit_failure("select: %s", strerror(errno));
|
||||
#endif
|
||||
}
|
||||
else if (error == 0)
|
||||
exit_failure("connection timeout");
|
||||
|
||||
@ -113,7 +181,12 @@ ftp_relay(int ctl6, int ctl4)
|
||||
* otherwise some of the pipe may become full and we cannot
|
||||
* relay correctly.
|
||||
*/
|
||||
if (FD_ISSET(ctl6, &readfds)) {
|
||||
#ifdef HAVE_POLL_H
|
||||
if (pfd[1].revents & POLLIN)
|
||||
#else
|
||||
if (FD_ISSET(ctl6, &readfds))
|
||||
#endif
|
||||
{
|
||||
/*
|
||||
* copy control connection from the client.
|
||||
* command translation is necessary.
|
||||
@ -126,9 +199,15 @@ ftp_relay(int ctl6, int ctl4)
|
||||
close(ctl4);
|
||||
close(ctl6);
|
||||
exit_success("terminating ftp control connection");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
if (FD_ISSET(ctl4, &readfds)) {
|
||||
#ifdef HAVE_POLL_H
|
||||
if (pfd[0].revents & POLLIN)
|
||||
#else
|
||||
if (FD_ISSET(ctl4, &readfds))
|
||||
#endif
|
||||
{
|
||||
/*
|
||||
* copy control connection from the server
|
||||
* translation of result code is necessary.
|
||||
@ -141,14 +220,24 @@ ftp_relay(int ctl6, int ctl4)
|
||||
close(ctl4);
|
||||
close(ctl6);
|
||||
exit_success("terminating ftp control connection");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
if (0 <= port4 && 0 <= port6 && FD_ISSET(port4, &readfds)) {
|
||||
#ifdef HAVE_POLL_H
|
||||
if (0 <= port4 && 0 <= port6 && (pfd[2].revents & POLLIN))
|
||||
#else
|
||||
if (0 <= port4 && 0 <= port6 && FD_ISSET(port4, &readfds))
|
||||
#endif
|
||||
{
|
||||
/*
|
||||
* copy data connection.
|
||||
* no special treatment necessary.
|
||||
*/
|
||||
#ifdef HAVE_POLL_H
|
||||
if (pfd[2].revents & POLLIN)
|
||||
#else
|
||||
if (FD_ISSET(port4, &readfds))
|
||||
#endif
|
||||
error = ftp_copy(port4, port6);
|
||||
switch (error) {
|
||||
case -1:
|
||||
@ -163,12 +252,21 @@ ftp_relay(int ctl6, int ctl4)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (0 <= port4 && 0 <= port6 && FD_ISSET(port6, &readfds)) {
|
||||
#ifdef HAVE_POLL_H
|
||||
if (0 <= port4 && 0 <= port6 && (pfd[3].revents & POLLIN))
|
||||
#else
|
||||
if (0 <= port4 && 0 <= port6 && FD_ISSET(port6, &readfds))
|
||||
#endif
|
||||
{
|
||||
/*
|
||||
* copy data connection.
|
||||
* no special treatment necessary.
|
||||
*/
|
||||
#ifdef HAVE_POLL_H
|
||||
if (pfd[3].revents & POLLIN)
|
||||
#else
|
||||
if (FD_ISSET(port6, &readfds))
|
||||
#endif
|
||||
error = ftp_copy(port6, port4);
|
||||
switch (error) {
|
||||
case -1:
|
||||
@ -184,13 +282,23 @@ ftp_relay(int ctl6, int ctl4)
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
if (wport4 && FD_ISSET(wport4, &readfds)) {
|
||||
#ifdef HAVE_POLL_H
|
||||
if (wport4 && (pfd[4].revents & POLLIN))
|
||||
#else
|
||||
if (wport4 && FD_ISSET(wport4, &readfds))
|
||||
#endif
|
||||
{
|
||||
/*
|
||||
* establish active data connection from the server.
|
||||
*/
|
||||
ftp_activeconn();
|
||||
}
|
||||
if (wport6 && FD_ISSET(wport6, &readfds)) {
|
||||
#ifdef HAVE_POLL_H
|
||||
if (wport4 && (pfd[5].revents & POLLIN))
|
||||
#else
|
||||
if (wport6 && FD_ISSET(wport6, &readfds))
|
||||
#endif
|
||||
{
|
||||
/*
|
||||
* establish passive data connection from the client.
|
||||
*/
|
||||
@ -206,20 +314,37 @@ ftp_relay(int ctl6, int ctl4)
|
||||
static int
|
||||
ftp_activeconn()
|
||||
{
|
||||
int n;
|
||||
socklen_t n;
|
||||
int error;
|
||||
#ifdef HAVE_POLL_H
|
||||
struct pollfd pfd[1];
|
||||
#else
|
||||
fd_set set;
|
||||
#endif
|
||||
struct timeval timeout;
|
||||
struct sockaddr *sa;
|
||||
|
||||
/* get active connection from server */
|
||||
#ifdef HAVE_POLL_H
|
||||
pfd[0].fd = wport4;
|
||||
pfd[0].events = POLLIN;
|
||||
#else
|
||||
FD_ZERO(&set);
|
||||
if (wport4 >= FD_SETSIZE)
|
||||
exit_failure("descriptor too big");
|
||||
FD_SET(wport4, &set);
|
||||
#endif
|
||||
timeout.tv_sec = 120;
|
||||
timeout.tv_usec = -1;
|
||||
timeout.tv_usec = 0;
|
||||
n = sizeof(data4);
|
||||
if (select(wport4 + 1, &set, NULL, NULL, &timeout) == 0
|
||||
|| (port4 = accept(wport4, (struct sockaddr *)&data4, &n)) < 0) {
|
||||
#ifdef HAVE_POLL_H
|
||||
if (poll(pfd, sizeof(pfd)/sizeof(pfd[0]), timeout.tv_sec * 1000) == 0 ||
|
||||
(port4 = accept(wport4, (struct sockaddr *)&data4, &n)) < 0)
|
||||
#else
|
||||
if (select(wport4 + 1, &set, NULL, NULL, &timeout) == 0 ||
|
||||
(port4 = accept(wport4, (struct sockaddr *)&data4, &n)) < 0)
|
||||
#endif
|
||||
{
|
||||
close(wport4);
|
||||
wport4 = -1;
|
||||
syslog(LOG_INFO, "active mode data connection failed");
|
||||
@ -253,20 +378,37 @@ ftp_activeconn()
|
||||
static int
|
||||
ftp_passiveconn()
|
||||
{
|
||||
int n;
|
||||
socklen_t len;
|
||||
int error;
|
||||
#ifdef HAVE_POLL_H
|
||||
struct pollfd pfd[1];
|
||||
#else
|
||||
fd_set set;
|
||||
#endif
|
||||
struct timeval timeout;
|
||||
struct sockaddr *sa;
|
||||
|
||||
/* get passive connection from client */
|
||||
#ifdef HAVE_POLL_H
|
||||
pfd[0].fd = wport6;
|
||||
pfd[0].events = POLLIN;
|
||||
#else
|
||||
FD_ZERO(&set);
|
||||
if (wport6 >= FD_SETSIZE)
|
||||
exit_failure("descriptor too big");
|
||||
FD_SET(wport6, &set);
|
||||
#endif
|
||||
timeout.tv_sec = 120;
|
||||
timeout.tv_usec = 0;
|
||||
n = sizeof(data6);
|
||||
if (select(wport6 + 1, &set, NULL, NULL, &timeout) == 0
|
||||
|| (port6 = accept(wport6, (struct sockaddr *)&data6, &n)) < 0) {
|
||||
len = sizeof(data6);
|
||||
#ifdef HAVE_POLL_H
|
||||
if (poll(pfd, sizeof(pfd)/sizeof(pfd[0]), timeout.tv_sec * 1000) == 0 ||
|
||||
(port6 = accept(wport6, (struct sockaddr *)&data6, &len)) < 0)
|
||||
#else
|
||||
if (select(wport6 + 1, &set, NULL, NULL, &timeout) == 0 ||
|
||||
(port6 = accept(wport6, (struct sockaddr *)&data6, &len)) < 0)
|
||||
#endif
|
||||
{
|
||||
close(wport6);
|
||||
wport6 = -1;
|
||||
syslog(LOG_INFO, "passive mode data connection failed");
|
||||
@ -300,8 +442,7 @@ ftp_passiveconn()
|
||||
static int
|
||||
ftp_copy(int src, int dst)
|
||||
{
|
||||
int error, atmark;
|
||||
int n;
|
||||
int error, atmark, n;
|
||||
|
||||
/* OOB data handling */
|
||||
error = ioctl(src, SIOCATMARK, &atmark);
|
||||
@ -338,10 +479,12 @@ ftp_copy(int src, int dst)
|
||||
static int
|
||||
ftp_copyresult(int src, int dst, enum state state)
|
||||
{
|
||||
int error, atmark;
|
||||
int n;
|
||||
int error, atmark, n;
|
||||
socklen_t len;
|
||||
char *param;
|
||||
int code;
|
||||
char *a, *p;
|
||||
int i;
|
||||
|
||||
/* OOB data handling */
|
||||
error = ioctl(src, SIOCATMARK, &atmark);
|
||||
@ -367,10 +510,6 @@ ftp_copyresult(int src, int dst, enum state state)
|
||||
/*
|
||||
* parse argument
|
||||
*/
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
p = rbuf;
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (!isdigit(*p)) {
|
||||
@ -392,7 +531,6 @@ ftp_copyresult(int src, int dst, enum state state)
|
||||
param++;
|
||||
if (!*param)
|
||||
param = NULL;
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case NONE:
|
||||
@ -400,15 +538,17 @@ ftp_copyresult(int src, int dst, enum state state)
|
||||
if (ftp_activeconn() < 0) {
|
||||
n = snprintf(rbuf, sizeof(rbuf),
|
||||
"425 Cannot open data connetion\r\n");
|
||||
if (n < 0 || n >= sizeof(rbuf))
|
||||
n = 0;
|
||||
}
|
||||
}
|
||||
return n > 0 ? write(dst, rbuf, n) : n;
|
||||
if (n)
|
||||
write(dst, rbuf, n);
|
||||
return n;
|
||||
case LPRT:
|
||||
case EPRT:
|
||||
/* expecting "200 PORT command successful." */
|
||||
if (code == 200) {
|
||||
char *p;
|
||||
|
||||
p = strstr(rbuf, "PORT");
|
||||
if (p) {
|
||||
p[0] = (state == LPRT) ? 'L' : 'E';
|
||||
@ -420,24 +560,6 @@ ftp_copyresult(int src, int dst, enum state state)
|
||||
}
|
||||
write(dst, rbuf, n);
|
||||
return n;
|
||||
#ifdef FAITH4
|
||||
case PORT:
|
||||
/* expecting "200 EPRT command successful." */
|
||||
if (code == 200) {
|
||||
char *p;
|
||||
|
||||
p = strstr(rbuf, "EPRT");
|
||||
if (p) {
|
||||
p[0] = 'P';
|
||||
p[1] = 'O';
|
||||
}
|
||||
} else {
|
||||
close(wport4);
|
||||
wport4 = -1;
|
||||
}
|
||||
write(dst, rbuf, n);
|
||||
return n;
|
||||
#endif
|
||||
case LPSV:
|
||||
case EPSV:
|
||||
/*
|
||||
@ -457,7 +579,6 @@ ftp_copyresult(int src, int dst, enum state state)
|
||||
struct sockaddr_in *sin;
|
||||
struct sockaddr_in6 *sin6;
|
||||
u_short port;
|
||||
char *p;
|
||||
|
||||
/*
|
||||
* PASV result -> LPSV/EPSV result
|
||||
@ -496,7 +617,11 @@ ftp_copyresult(int src, int dst, enum state state)
|
||||
passivefail:
|
||||
n = snprintf(sbuf, sizeof(sbuf),
|
||||
"500 could not translate from PASV\r\n");
|
||||
return n > 0 ? write(src, sbuf, n) : n;
|
||||
if (n < 0 || n >= sizeof(sbuf))
|
||||
n = 0;
|
||||
if (n)
|
||||
write(src, sbuf, n);
|
||||
return n;
|
||||
}
|
||||
#ifdef IPV6_FAITH
|
||||
{
|
||||
@ -524,8 +649,8 @@ ftp_copyresult(int src, int dst, enum state state)
|
||||
/*
|
||||
* addr from dst, port from wport6
|
||||
*/
|
||||
n = sizeof(data6);
|
||||
error = getsockname(wport6, (struct sockaddr *)&data6, &n);
|
||||
len = sizeof(data6);
|
||||
error = getsockname(wport6, (struct sockaddr *)&data6, &len);
|
||||
if (error == -1) {
|
||||
close(wport6);
|
||||
wport6 = -1;
|
||||
@ -534,8 +659,8 @@ ftp_copyresult(int src, int dst, enum state state)
|
||||
sin6 = (struct sockaddr_in6 *)&data6;
|
||||
port = sin6->sin6_port;
|
||||
|
||||
n = sizeof(data6);
|
||||
error = getsockname(dst, (struct sockaddr *)&data6, &n);
|
||||
len = sizeof(data6);
|
||||
error = getsockname(dst, (struct sockaddr *)&data6, &len);
|
||||
if (error == -1) {
|
||||
close(wport6);
|
||||
wport6 = -1;
|
||||
@ -545,8 +670,6 @@ ftp_copyresult(int src, int dst, enum state state)
|
||||
sin6->sin6_port = port;
|
||||
|
||||
if (state == LPSV) {
|
||||
char *a, *p;
|
||||
|
||||
a = (char *)&sin6->sin6_addr;
|
||||
p = (char *)&sin6->sin6_port;
|
||||
n = snprintf(sbuf, sizeof(sbuf),
|
||||
@ -556,132 +679,24 @@ ftp_copyresult(int src, int dst, enum state state)
|
||||
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 = write(dst, sbuf, n);
|
||||
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 = write(dst, sbuf, n);
|
||||
if (n < 0 || n >= sizeof(sbuf))
|
||||
n = 0;
|
||||
if (n)
|
||||
write(dst, sbuf, n);
|
||||
passivemode = 1;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
#ifdef FAITH4
|
||||
case PASV:
|
||||
/* expecting "229 Entering Extended Passive Mode (|||x|)" */
|
||||
if (code != 229) {
|
||||
passivefail1:
|
||||
close(wport6);
|
||||
wport6 = -1;
|
||||
write(dst, rbuf, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
{
|
||||
u_short port;
|
||||
char *p;
|
||||
struct sockaddr_in *sin;
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
/*
|
||||
* EPSV result -> PORT result
|
||||
*/
|
||||
p = param;
|
||||
while (*p && *p != '(') /*)*/
|
||||
p++;
|
||||
if (!*p)
|
||||
goto passivefail1; /*XXX*/
|
||||
p++;
|
||||
n = sscanf(p, "|||%hu|", &port);
|
||||
if (n != 1)
|
||||
goto passivefail1; /*XXX*/
|
||||
|
||||
/* keep EPRT parameter */
|
||||
n = sizeof(data4);
|
||||
error = getpeername(src, (struct sockaddr *)&data4, &n);
|
||||
if (error == -1)
|
||||
goto passivefail1; /*XXX*/
|
||||
sin6 = (struct sockaddr_in6 *)&data4;
|
||||
sin6->sin6_port = htons(port);
|
||||
|
||||
/* get ready for passive data connection */
|
||||
memset(&data6, 0, sizeof(data6));
|
||||
sin = (struct sockaddr_in *)&data6;
|
||||
sin->sin_len = sizeof(*sin);
|
||||
sin->sin_family = AF_INET;
|
||||
wport6 = socket(sin->sin_family, SOCK_STREAM, 0);
|
||||
if (wport6 == -1) {
|
||||
passivefail2:
|
||||
n = snprintf(sbuf, sizeof(sbuf),
|
||||
"500 could not translate from EPSV\r\n");
|
||||
return n > 0 ? write(src, sbuf, n) : n;
|
||||
}
|
||||
#ifdef IP_FAITH
|
||||
{
|
||||
int on = 1;
|
||||
error = setsockopt(wport6, IPPROTO_IP, IP_FAITH,
|
||||
&on, sizeof(on));
|
||||
if (error == -1)
|
||||
exit_error("setsockopt(IP_FAITH): %s", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
error = bind(wport6, (struct sockaddr *)sin, sin->sin_len);
|
||||
if (error == -1) {
|
||||
close(wport6);
|
||||
wport6 = -1;
|
||||
goto passivefail2;
|
||||
}
|
||||
error = listen(wport6, 1);
|
||||
if (error == -1) {
|
||||
close(wport6);
|
||||
wport6 = -1;
|
||||
goto passivefail2;
|
||||
}
|
||||
|
||||
/* transmit PORT */
|
||||
/*
|
||||
* addr from dst, port from wport6
|
||||
*/
|
||||
n = sizeof(data6);
|
||||
error = getsockname(wport6, (struct sockaddr *)&data6, &n);
|
||||
if (error == -1) {
|
||||
close(wport6);
|
||||
wport6 = -1;
|
||||
goto passivefail2;
|
||||
}
|
||||
sin = (struct sockaddr_in *)&data6;
|
||||
port = sin->sin_port;
|
||||
|
||||
n = sizeof(data6);
|
||||
error = getsockname(dst, (struct sockaddr *)&data6, &n);
|
||||
if (error == -1) {
|
||||
close(wport6);
|
||||
wport6 = -1;
|
||||
goto passivefail2;
|
||||
}
|
||||
sin = (struct sockaddr_in *)&data6;
|
||||
sin->sin_port = port;
|
||||
|
||||
{
|
||||
char *a, *p;
|
||||
|
||||
a = (char *)&sin->sin_addr;
|
||||
p = (char *)&sin->sin_port;
|
||||
n = snprintf(sbuf, sizeof(sbuf),
|
||||
"227 Entering Passive Mode (%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 = write(dst, sbuf, n);
|
||||
passivemode = 1;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
#endif /* FAITH4 */
|
||||
}
|
||||
|
||||
bad:
|
||||
@ -693,15 +708,16 @@ ftp_copyresult(int src, int dst, enum state state)
|
||||
static int
|
||||
ftp_copycommand(int src, int dst, enum state *state)
|
||||
{
|
||||
int error, atmark;
|
||||
int n;
|
||||
int error, atmark, n;
|
||||
socklen_t len;
|
||||
unsigned int af, hal, ho[16], pal, po[2];
|
||||
char *a, *p;
|
||||
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);
|
||||
@ -732,10 +748,6 @@ ftp_copycommand(int src, int dst, enum state *state)
|
||||
/*
|
||||
* parse argument
|
||||
*/
|
||||
{
|
||||
char *p, *q;
|
||||
int i;
|
||||
|
||||
p = rbuf;
|
||||
q = cmd;
|
||||
for (i = 0; i < 4; i++) {
|
||||
@ -759,7 +771,6 @@ ftp_copycommand(int src, int dst, enum state *state)
|
||||
param++;
|
||||
if (!*param)
|
||||
param = NULL;
|
||||
}
|
||||
|
||||
*state = NONE;
|
||||
|
||||
@ -778,7 +789,11 @@ ftp_copycommand(int src, int dst, enum state *state)
|
||||
if (epsvall) {
|
||||
n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
|
||||
cmd);
|
||||
return n > 0 ? write(src, sbuf, n) : n;
|
||||
if (n < 0 || n >= sizeof(sbuf))
|
||||
n = 0;
|
||||
if (n)
|
||||
write(src, sbuf, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
n = sscanf(param,
|
||||
@ -791,7 +806,11 @@ ftp_copycommand(int src, int dst, enum state *state)
|
||||
if (n != 21 || af != 6 || hal != 16|| pal != 2) {
|
||||
n = snprintf(sbuf, sizeof(sbuf),
|
||||
"501 illegal parameter to LPRT\r\n");
|
||||
return n > 0 ? write(src, sbuf, n) : n;
|
||||
if (n < 0 || n >= sizeof(sbuf))
|
||||
n = 0;
|
||||
if (n)
|
||||
write(src, sbuf, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
/* keep LPRT parameter */
|
||||
@ -805,13 +824,17 @@ ftp_copycommand(int src, int dst, enum state *state)
|
||||
|
||||
sendport:
|
||||
/* get ready for active data connection */
|
||||
n = sizeof(data4);
|
||||
error = getsockname(dst, (struct sockaddr *)&data4, &n);
|
||||
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");
|
||||
return n > 0 ? write(src, sbuf, n) : 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;
|
||||
@ -834,8 +857,8 @@ ftp_copycommand(int src, int dst, enum state *state)
|
||||
}
|
||||
|
||||
/* transmit PORT */
|
||||
n = sizeof(data4);
|
||||
error = getsockname(wport4, (struct sockaddr *)&data4, &n);
|
||||
len = sizeof(data4);
|
||||
error = getsockname(wport4, (struct sockaddr *)&data4, &len);
|
||||
if (error == -1) {
|
||||
close(wport4);
|
||||
wport4 = -1;
|
||||
@ -852,8 +875,10 @@ ftp_copycommand(int src, int dst, enum state *state)
|
||||
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 = write(dst, sbuf, n);
|
||||
if (n < 0 || n >= sizeof(sbuf))
|
||||
n = 0;
|
||||
if (n)
|
||||
write(dst, sbuf, n);
|
||||
*state = nstate;
|
||||
passivemode = 0;
|
||||
return n;
|
||||
@ -875,7 +900,11 @@ ftp_copycommand(int src, int dst, enum state *state)
|
||||
if (epsvall) {
|
||||
n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
|
||||
cmd);
|
||||
return n > 0 ? write(src, sbuf, n) : n;
|
||||
if (n < 0 || n >= sizeof(sbuf))
|
||||
n = 0;
|
||||
if (n)
|
||||
write(src, sbuf, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
p = param;
|
||||
@ -887,7 +916,11 @@ ftp_copycommand(int src, int dst, enum state *state)
|
||||
eprtparamfail:
|
||||
n = snprintf(sbuf, sizeof(sbuf),
|
||||
"501 illegal parameter to EPRT\r\n");
|
||||
return n > 0 ? write(src, sbuf, n) : n;
|
||||
if (n < 0 || n >= sizeof(sbuf))
|
||||
n = 0;
|
||||
if (n)
|
||||
write(src, sbuf, n);
|
||||
return n;
|
||||
}
|
||||
*p++ = '\0';
|
||||
hostp = p;
|
||||
@ -907,21 +940,34 @@ ftp_copycommand(int src, int dst, enum state *state)
|
||||
if (n != 1 || af != 2) {
|
||||
n = snprintf(sbuf, sizeof(sbuf),
|
||||
"501 unsupported address family to EPRT\r\n");
|
||||
return n > 0 ? write(src, sbuf, n) : 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));
|
||||
return n > 0 ? write(src, sbuf, n) : n;
|
||||
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);
|
||||
return n > 0 ? write(src, sbuf, n) : n;
|
||||
if (n < 0 || n >= sizeof(sbuf))
|
||||
n = 0;
|
||||
if (n)
|
||||
write(src, sbuf, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
memcpy(&data6, res->ai_addr, res->ai_addrlen);
|
||||
@ -942,13 +988,19 @@ ftp_copycommand(int src, int dst, enum state *state)
|
||||
if (epsvall) {
|
||||
n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
|
||||
cmd);
|
||||
return n > 0 ? write(src, sbuf, n) : n;
|
||||
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 = write(dst, sbuf, 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;
|
||||
@ -963,8 +1015,10 @@ ftp_copycommand(int src, int dst, enum state *state)
|
||||
wport4 = wport6 = port4 = port6 = -1;
|
||||
|
||||
n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n");
|
||||
if (n > 0)
|
||||
n = write(dst, sbuf, 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;
|
||||
@ -975,120 +1029,21 @@ ftp_copycommand(int src, int dst, enum state *state)
|
||||
*/
|
||||
epsvall = 1;
|
||||
n = snprintf(sbuf, sizeof(sbuf), "200 EPSV ALL command successful.\r\n");
|
||||
return n > 0 ? write(src, sbuf, n) : n;
|
||||
#ifdef FAITH4
|
||||
} else if (strcmp(cmd, "PORT") == 0 && param) {
|
||||
/*
|
||||
* PORT -> EPRT
|
||||
*/
|
||||
char host[NI_MAXHOST], serv[NI_MAXSERV];
|
||||
|
||||
nstate = PORT;
|
||||
|
||||
close(wport4);
|
||||
close(wport6);
|
||||
close(port4);
|
||||
close(port6);
|
||||
wport4 = wport6 = port4 = port6 = -1;
|
||||
|
||||
p = param;
|
||||
n = sscanf(p, "%u,%u,%u,%u,%u,%u",
|
||||
&ho[0], &ho[1], &ho[2], &ho[3], &po[0], &po[1]);
|
||||
if (n != 6) {
|
||||
n = snprintf(sbuf, sizeof(sbuf),
|
||||
"501 illegal parameter to PORT\r\n");
|
||||
return n > 0 ? write(src, sbuf, n) : n;
|
||||
}
|
||||
|
||||
memset(&data6, 0, sizeof(data6));
|
||||
sin = (struct sockaddr_in *)&data6;
|
||||
sin->sin_len = sizeof(*sin);
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_addr.s_addr = htonl(
|
||||
((ho[0] & 0xff) << 24) | ((ho[1] & 0xff) << 16) |
|
||||
((ho[2] & 0xff) << 8) | (ho[3] & 0xff));
|
||||
sin->sin_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff));
|
||||
|
||||
/* get ready for active data connection */
|
||||
n = sizeof(data4);
|
||||
error = getsockname(dst, (struct sockaddr *)&data4, &n);
|
||||
if (error == -1) {
|
||||
portfail:
|
||||
n = snprintf(sbuf, sizeof(sbuf),
|
||||
"500 could not translate to EPRT\r\n");
|
||||
return n > 0 ? write(src, sbuf, n) : n;
|
||||
}
|
||||
if (((struct sockaddr *)&data4)->sa_family != AF_INET6)
|
||||
goto portfail;
|
||||
|
||||
((struct sockaddr_in6 *)&data4)->sin6_port = 0;
|
||||
sa = (struct sockaddr *)&data4;
|
||||
wport4 = socket(sa->sa_family, SOCK_STREAM, 0);
|
||||
if (wport4 == -1)
|
||||
goto portfail;
|
||||
error = bind(wport4, sa, sa->sa_len);
|
||||
if (error == -1) {
|
||||
close(wport4);
|
||||
wport4 = -1;
|
||||
goto portfail;
|
||||
}
|
||||
error = listen(wport4, 1);
|
||||
if (error == -1) {
|
||||
close(wport4);
|
||||
wport4 = -1;
|
||||
goto portfail;
|
||||
}
|
||||
|
||||
/* transmit EPRT */
|
||||
n = sizeof(data4);
|
||||
error = getsockname(wport4, (struct sockaddr *)&data4, &n);
|
||||
if (error == -1) {
|
||||
close(wport4);
|
||||
wport4 = -1;
|
||||
goto portfail;
|
||||
}
|
||||
af = 2;
|
||||
sa = (struct sockaddr *)&data4;
|
||||
if (getnameinfo(sa, sa->sa_len, host, sizeof(host),
|
||||
serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV)) {
|
||||
close(wport4);
|
||||
wport4 = -1;
|
||||
goto portfail;
|
||||
}
|
||||
n = snprintf(sbuf, sizeof(sbuf), "EPRT |%d|%s|%s|\r\n", af, host, serv);
|
||||
if (n > 0)
|
||||
n = write(dst, sbuf, n);
|
||||
*state = nstate;
|
||||
passivemode = 0;
|
||||
if (n < 0 || n >= sizeof(sbuf))
|
||||
n = 0;
|
||||
if (n)
|
||||
write(src, sbuf, n);
|
||||
return n;
|
||||
} else if (strcmp(cmd, "PASV") == 0 && !param) {
|
||||
/*
|
||||
* PASV -> EPSV
|
||||
*/
|
||||
|
||||
nstate = PASV;
|
||||
|
||||
close(wport4);
|
||||
close(wport6);
|
||||
close(port4);
|
||||
close(port6);
|
||||
wport4 = wport6 = port4 = port6 = -1;
|
||||
|
||||
/* transmit EPSV */
|
||||
n = snprintf(sbuf, sizeof(sbuf), "EPSV\r\n");
|
||||
if (n > 0)
|
||||
n = write(dst, sbuf, n);
|
||||
*state = PASV;
|
||||
passivemode = 0; /* to be set to 1 later */
|
||||
return n;
|
||||
#else /* FAITH4 */
|
||||
} 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);
|
||||
return n > 0 ? write(src, sbuf, n) : n;
|
||||
#endif /* FAITH4 */
|
||||
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
|
||||
@ -1103,8 +1058,10 @@ ftp_copycommand(int src, int dst, enum state *state)
|
||||
|
||||
if (ftp_passiveconn() < 0) {
|
||||
n = snprintf(sbuf, sizeof(sbuf), "425 Cannot open data connetion\r\n");
|
||||
if (n > 0)
|
||||
n = write(src, sbuf, n);
|
||||
if (n < 0 || n >= sizeof(sbuf))
|
||||
n = 0;
|
||||
if (n)
|
||||
write(src, sbuf, n);
|
||||
} else {
|
||||
/* simply relay the command */
|
||||
write(dst, rbuf, n);
|
||||
@ -1115,7 +1072,8 @@ ftp_copycommand(int src, int dst, enum state *state)
|
||||
} else {
|
||||
/* simply relay it */
|
||||
*state = NONE;
|
||||
return write(dst, rbuf, n);
|
||||
write(dst, rbuf, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
bad:
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $KAME: prefix.c,v 1.9 2001/07/02 14:36:49 itojun Exp $ */
|
||||
/* $KAME: prefix.c,v 1.13 2003/09/02 22:50:17 itojun Exp $ */
|
||||
/* $FreeBSD$ */
|
||||
|
||||
/*
|
||||
@ -58,17 +58,16 @@ struct config *config_list = NULL;
|
||||
const int niflags = NI_NUMERICHOST;
|
||||
|
||||
static int
|
||||
prefix_set(s, prefix, slash)
|
||||
const char *s;
|
||||
struct prefix *prefix;
|
||||
int slash;
|
||||
prefix_set(const char *s, struct prefix *prefix, int slash)
|
||||
{
|
||||
char *p, *q, *r;
|
||||
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)
|
||||
@ -126,8 +125,7 @@ prefix_set(s, prefix, slash)
|
||||
}
|
||||
|
||||
const char *
|
||||
prefix_string(prefix)
|
||||
const struct prefix *prefix;
|
||||
prefix_string(const struct prefix *prefix)
|
||||
{
|
||||
static char buf[NI_MAXHOST + 20];
|
||||
char hbuf[NI_MAXHOST];
|
||||
@ -140,9 +138,7 @@ prefix_string(prefix)
|
||||
}
|
||||
|
||||
int
|
||||
prefix_match(prefix, sa)
|
||||
const struct prefix *prefix;
|
||||
const struct sockaddr *sa;
|
||||
prefix_match(const struct prefix *prefix, const struct sockaddr *sa)
|
||||
{
|
||||
struct sockaddr_storage a, b;
|
||||
char *pa, *pb;
|
||||
@ -194,8 +190,7 @@ prefix_match(prefix, sa)
|
||||
* 3ffe::/16 permit 10.0.0.0/8 10.1.1.1
|
||||
*/
|
||||
static struct config *
|
||||
config_load1(line)
|
||||
const char *line;
|
||||
config_load1(const char *line)
|
||||
{
|
||||
struct config *conf;
|
||||
char buf[BUFSIZ];
|
||||
@ -268,8 +263,7 @@ config_load1(line)
|
||||
}
|
||||
|
||||
int
|
||||
config_load(configfile)
|
||||
const char *configfile;
|
||||
config_load(const char *configfile)
|
||||
{
|
||||
FILE *fp;
|
||||
char buf[BUFSIZ];
|
||||
@ -285,6 +279,7 @@ config_load(configfile)
|
||||
return -1;
|
||||
|
||||
p = &sentinel;
|
||||
sentinel.next = NULL;
|
||||
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
||||
conf = config_load1(buf);
|
||||
if (conf) {
|
||||
@ -300,8 +295,7 @@ config_load(configfile)
|
||||
|
||||
#if 0
|
||||
static void
|
||||
config_show1(conf)
|
||||
const struct config *conf;
|
||||
config_show1(const struct config *conf)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
@ -330,8 +324,7 @@ config_show()
|
||||
#endif
|
||||
|
||||
const struct config *
|
||||
config_match(sa1, sa2)
|
||||
struct sockaddr *sa1, *sa2;
|
||||
config_match(struct sockaddr *sa1, struct sockaddr *sa2)
|
||||
{
|
||||
static struct config conf;
|
||||
const struct config *p;
|
||||
|
@ -1,212 +0,0 @@
|
||||
/* $KAME: rsh.c,v 1.7 2001/09/05 01:10: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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#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, strerror(errno));
|
||||
else if (error == 0)
|
||||
exit_failure("connection 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("%s", strerror(errno));
|
||||
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;
|
||||
struct sockaddr *sa;
|
||||
|
||||
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 (((struct sockaddr *)&ctladdr6)->sa_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);
|
||||
|
||||
sa = (struct sockaddr *)&ctladdr6;
|
||||
s_ctl6 = rresvport_af(&lport6, sa->sa_family);
|
||||
if (s_ctl6 == -1) goto bad;
|
||||
error = connect(s_ctl6, sa, sa->sa_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", strerror(errno));
|
||||
else if (error == 0)
|
||||
exit_failure("connection 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("%s", strerror(errno));
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* $KAME: tcp.c,v 1.8 2001/11/21 07:40:22 itojun Exp $ */
|
||||
/* $KAME: tcp.c,v 1.13 2003/09/02 22:49:21 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1997 and 1998 WIDE Project.
|
||||
@ -93,8 +93,9 @@ sig_child(int sig)
|
||||
pid_t pid;
|
||||
|
||||
pid = wait3(&status, WNOHANG, (struct rusage *)0);
|
||||
if (pid && WEXITSTATUS(status))
|
||||
syslog(LOG_WARNING, "child %d exit status 0x%x", pid, status);
|
||||
if (pid > 0 && WEXITSTATUS(status))
|
||||
syslog(LOG_WARNING, "child %ld exit status 0x%x",
|
||||
(long)pid, status);
|
||||
exit_success("terminate connection due to child termination");
|
||||
}
|
||||
|
||||
@ -156,6 +157,8 @@ send_data(int s_rcv, int s_snd, const char *service, int direction)
|
||||
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);
|
||||
}
|
||||
|
||||
@ -174,12 +177,18 @@ send_data(int s_rcv, int s_snd, const char *service, int direction)
|
||||
}
|
||||
#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);
|
||||
}
|
||||
|
||||
@ -195,6 +204,8 @@ relay(int s_rcv, int s_snd, const char *service, int direction)
|
||||
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;
|
||||
@ -229,7 +240,11 @@ relay(int s_rcv, int s_snd, const char *service, int direction)
|
||||
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) {
|
||||
@ -262,7 +277,11 @@ relay(int s_rcv, int s_snd, const char *service, int direction)
|
||||
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;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
# highly experimental (not working right at all) and very limited
|
||||
# functionality.
|
||||
#
|
||||
# $Id: faithd.rb,v 1.1.1.1 1999/08/08 23:29:31 itojun Exp $
|
||||
# $Id: faithd.rb,v 1.1.2.4 1999/05/10 17:06:30 itojun Exp $
|
||||
# $FreeBSD$
|
||||
|
||||
require "socket"
|
||||
|
Loading…
Reference in New Issue
Block a user