another tcp apps IPv6 updates.(should be make world safe)

ftp, telnet, ftpd, faithd
  also telnet related sync with crypto, secure, kerberosIV

Obtained from: KAME project
This commit is contained in:
Yoshinobu Inoue 2000-01-27 09:28:38 +00:00
parent 404d72b9f6
commit 4dd8b5ab79
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=56668
48 changed files with 5716 additions and 869 deletions

View File

@ -29,6 +29,8 @@
* 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$
*/
#ifndef lint
@ -83,6 +85,7 @@ static const char sccsid[] = "@(#)commands.c 8.4 (Berkeley) 5/30/95";
# endif /* vax */
#endif /* !defined(CRAY) && !defined(sysV88) */
#include <netinet/ip.h>
#include <netinet/ip6.h>
#ifndef MAXHOSTNAMELEN
@ -2270,27 +2273,76 @@ ayt_status()
}
#endif
unsigned long inet_addr();
static const char *
sockaddr_ntop(sa)
struct sockaddr *sa;
{
void *addr;
static char addrbuf[INET6_ADDRSTRLEN];
switch (sa->sa_family) {
case AF_INET:
addr = &((struct sockaddr_in *)sa)->sin_addr;
break;
#ifdef INET6
case AF_INET6:
addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
break;
#endif
default:
return NULL;
}
inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf));
return addrbuf;
}
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
static int
setpolicy(net, res, policy)
int net;
struct addrinfo *res;
char *policy;
{
char *buf;
int level;
int optname;
if (policy == NULL)
return 0;
buf = ipsec_set_policy(policy, strlen(policy));
if (buf == NULL) {
printf("%s\n", ipsec_strerror());
return -1;
}
level = res->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
optname = res->ai_family == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY;
if (setsockopt(net, level, optname, buf, ipsec_get_policylen(buf)) < 0){
perror("setsockopt");
return -1;
}
free(buf);
}
#endif
int
tn(argc, argv)
int argc;
char *argv[];
{
register struct hostent *host = 0;
struct sockaddr_in sin, src_sin;
struct servent *sp = 0;
unsigned long temp;
extern char *inet_ntoa();
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
struct sockaddr_storage ss, src_ss;
char *srp = 0, *strrchr();
unsigned long sourceroute(), srlen;
#endif
int proto, opt;
int sourceroute(), srlen;
int srcroute = 0, result;
char *cmd, *hostp = 0, *portp = 0, *user = 0;
char *src_addr = NULL;
struct addrinfo hints, *res;
int error = 0;
/* clear the socket address prior to use */
memset((char *)&sin, 0, sizeof(sin));
memset((char *)&ss, 0, sizeof(ss));
if (connected) {
printf("?Already connected to %s\n", hostname);
@ -2350,126 +2402,106 @@ tn(argc, argv)
goto usage;
if (src_addr != NULL) {
bzero((char *)&src_sin, sizeof(src_sin));
src_sin.sin_family = AF_INET;
if (!inet_aton(src_addr, &src_sin.sin_addr)) {
host = gethostbyname2(src_addr, AF_INET);
if (host == NULL) {
herror(src_addr);
return 0;
}
if (host->h_length != sizeof(src_sin.sin_addr)) {
fprintf(stderr, "telnet: gethostbyname2: invalid address\n");
return 0;
}
memcpy((void *)&src_sin.sin_addr, (void *)host->h_addr_list[0],
sizeof(src_sin.sin_addr));
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(src_addr, 0, &hints, &res);
if (error == EAI_NONAME) {
hints.ai_flags = 0;
error = getaddrinfo(src_addr, 0, &hints, &res);
}
if (error != 0) {
fprintf(stderr, "%s: %s\n", src_addr, gai_strerror(error));
if (error == EAI_SYSTEM)
fprintf(stderr, "%s: %s\n", src_addr, strerror(errno));
return 0;
}
memcpy((void *)&src_ss, (void *)res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
}
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
if (hostp[0] == '@' || hostp[0] == '!') {
if ((hostname = strrchr(hostp, ':')) == NULL)
if (
#ifdef INET6
family == AF_INET6 ||
#endif
(hostname = strrchr(hostp, ':')) == NULL)
hostname = strrchr(hostp, '@');
hostname++;
srp = 0;
temp = sourceroute(hostp, &srp, &srlen);
if (temp == 0) {
herror(srp);
srcroute = 1;
} else
hostname = hostp;
if (!portp) {
telnetport = 1;
portp = "telnet";
} else if (*portp == '-') {
portp++;
telnetport = 1;
} else
telnetport = 0;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(hostname, portp, &hints, &res);
if (error == 0) {
int gni_err = 1;
if (doaddrlookup)
gni_err = getnameinfo(res->ai_addr, res->ai_addr->sa_len,
_hostname, sizeof(_hostname) - 1, NULL, 0,
0);
if (gni_err != 0)
(void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
_hostname[sizeof(_hostname)-1] = '\0';
hostname = _hostname;
} else if (error == EAI_NONAME) {
hints.ai_flags = AI_CANONNAME;
error = getaddrinfo(hostname, portp, &hints, &res);
if (error != 0) {
fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error));
if (error == EAI_SYSTEM)
fprintf(stderr, "%s: %s\n", hostname, strerror(errno));
setuid(getuid());
return 0;
} else if (temp == -1) {
}
memcpy((void *)&ss, (void *)res->ai_addr, res->ai_addrlen);
if (srcroute != 0)
(void) strncpy(_hostname, hostname, sizeof(_hostname) - 1);
else if (res->ai_canonname != NULL)
strcpy(_hostname, res->ai_canonname);
else
(void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
_hostname[sizeof(_hostname)-1] = '\0';
hostname = _hostname;
}
if (srcroute != 0) {
srp = 0;
result = sourceroute(res, hostp, &srp, &srlen, &proto, &opt);
if (result == 0) {
setuid(getuid());
freeaddrinfo(res);
return 0;
} else if (result == -1) {
printf("Bad source route option: %s\n", hostp);
setuid(getuid());
freeaddrinfo(res);
return 0;
} else {
sin.sin_addr.s_addr = temp;
sin.sin_family = AF_INET;
}
} else {
#endif
temp = inet_addr(hostp);
if (temp != INADDR_NONE) {
sin.sin_addr.s_addr = temp;
sin.sin_family = AF_INET;
if (doaddrlookup)
host = gethostbyaddr((char *)&temp, sizeof(temp), AF_INET);
if (host)
(void) strncpy(_hostname, host->h_name, sizeof(_hostname));
else
(void) strncpy(_hostname, hostp, sizeof(_hostname));
_hostname[sizeof(_hostname)-1] = '\0';
hostname = _hostname;
} else {
host = gethostbyname(hostp);
if (host) {
sin.sin_family = host->h_addrtype;
#if defined(h_addr) /* In 4.3, this is a #define */
memmove((caddr_t)&sin.sin_addr,
host->h_addr_list[0], host->h_length);
#else /* defined(h_addr) */
memmove((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
#endif /* defined(h_addr) */
strncpy(_hostname, host->h_name, sizeof(_hostname));
_hostname[sizeof(_hostname)-1] = '\0';
hostname = _hostname;
} else {
herror(hostp);
setuid(getuid());
return 0;
}
}
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
}
#endif
if (portp) {
if (*portp == '-') {
portp++;
telnetport = 1;
} else
telnetport = 0;
sin.sin_port = atoi(portp);
if (sin.sin_port == 0) {
sp = getservbyname(portp, "tcp");
if (sp)
sin.sin_port = sp->s_port;
else {
printf("%s: bad port number\n", portp);
setuid(getuid());
return 0;
}
} else {
#if !defined(htons)
u_short htons P((unsigned short));
#endif /* !defined(htons) */
sin.sin_port = htons(sin.sin_port);
}
} else {
if (sp == 0) {
sp = getservbyname("telnet", "tcp");
if (sp == 0) {
fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
setuid(getuid());
return 0;
}
sin.sin_port = sp->s_port;
}
telnetport = 1;
}
printf("Trying %s...\n", inet_ntoa(sin.sin_addr));
printf("Trying %s...\n", sockaddr_ntop(res->ai_addr));
do {
net = socket(AF_INET, SOCK_STREAM, 0);
net = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
setuid(getuid());
if (net < 0) {
perror("telnet: socket");
return 0;
}
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
perror("setsockopt (IP_OPTIONS)");
#endif
if (srp && setsockopt(net, proto, opt, (char *)srp, srlen) < 0)
perror("setsockopt (source route)");
#if defined(IPPROTO_IP) && defined(IP_TOS)
{
if (res->ai_family == PF_INET) {
# if defined(HAS_GETTOS)
struct tosent *tp;
if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
@ -2490,28 +2522,31 @@ tn(argc, argv)
}
if (src_addr != NULL) {
if (bind(net, (struct sockaddr *)&src_sin, sizeof(src_sin)) == -1) {
if (bind(net, (struct sockaddr *)&src_ss,
((struct sockaddr *)&src_ss)->sa_len) == -1) {
perror("bind");
return 0;
}
}
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
if (setpolicy(net, res, ipsec_policy_in) < 0)
return 0;
if (setpolicy(net, res, ipsec_policy_out) < 0)
return 0;
#endif
if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
#if defined(h_addr) /* In 4.3, this is a #define */
if (host && host->h_addr_list[1]) {
if (connect(net, res->ai_addr, res->ai_addrlen) < 0) {
if (res->ai_next) {
int oerrno = errno;
fprintf(stderr, "telnet: connect to address %s: ",
inet_ntoa(sin.sin_addr));
sockaddr_ntop(res->ai_addr));
errno = oerrno;
perror((char *)0);
host->h_addr_list++;
memmove((caddr_t)&sin.sin_addr,
host->h_addr_list[0], host->h_length);
res = res->ai_next;
(void) NetClose(net);
continue;
}
#endif /* defined(h_addr) */
perror("telnet: Unable to connect to remote host");
return 0;
}
@ -2520,6 +2555,7 @@ tn(argc, argv)
auth_encrypt_connect(connected);
#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
} while (connected == 0);
freeaddrinfo(res);
cmdrc(hostp, hostname);
if (autologin && user == NULL) {
struct passwd *pw;
@ -2861,8 +2897,6 @@ cmdrc(m1, m2)
fclose(rcfile);
}
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
/*
* Source route is handed in as
* [!]@hop1@hop2...[@|:]dst
@ -2876,6 +2910,10 @@ cmdrc(m1, m2)
* be the address to connect() to.
*
* Arguments:
*
* res: ponter to addrinfo structure which contains sockaddr to
* the host to connect to.
*
* arg: pointer to route list to decipher
*
* cpp: If *cpp is not equal to NULL, this is a
@ -2885,9 +2923,18 @@ cmdrc(m1, m2)
* lenp: pointer to an integer that contains the
* length of *cpp if *cpp != NULL.
*
* protop: pointer to an integer that should be filled in with
* appropriate protocol for setsockopt, as socket
* protocol family.
*
* optp: pointer to an integer that should be filled in with
* appropriate option for setsockopt, as socket protocol
* family.
*
* Return values:
*
* Returns the address of the host to connect to. If the
* If the return value is 1, then all operations are
* successful. If the
* return value is -1, there was a syntax error in the
* option, either unknown characters, or too many hosts.
* If the return value is 0, one of the hostnames in the
@ -2901,21 +2948,32 @@ cmdrc(m1, m2)
* *lenp: This will be filled in with how long the option
* pointed to by *cpp is.
*
* *protop: This will be filled in with appropriate protocol for
* setsockopt, as socket protocol family.
*
* *optp: This will be filled in with appropriate option for
* setsockopt, as socket protocol family.
*/
unsigned long
sourceroute(arg, cpp, lenp)
int
sourceroute(ai, arg, cpp, lenp, protop, optp)
struct addrinfo *ai;
char *arg;
char **cpp;
int *lenp;
int *protop;
int *optp;
{
static char lsr[44];
static char buf[1024]; /*XXX*/
struct cmsghdr *cmsg;
#ifdef sysV88
static IOPTN ipopt;
#endif
char *cp, *cp2, *lsrp, *lsrep;
char *cp, *cp2, *lsrp, *ep;
register int tmp;
struct in_addr sin_addr;
register struct hostent *host = 0;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
struct addrinfo hints, *res;
int error;
register char c;
/*
@ -2924,22 +2982,46 @@ sourceroute(arg, cpp, lenp)
*/
if (cpp == NULL || lenp == NULL)
return((unsigned long)-1);
if (*cpp != NULL && *lenp < 7)
return((unsigned long)-1);
if (*cpp != NULL) {
switch (res->ai_family) {
case AF_INET:
if (*lenp < 7)
return((unsigned long)-1);
break;
#ifdef INET6
case AF_INET6:
if (*lenp < (sizeof(struct cmsghdr) +
sizeof(struct ip6_rthdr) +
sizeof(struct in6_addr)))
return((unsigned long)-1);
break;
#endif
}
}
/*
* Decide whether we have a buffer passed to us,
* or if we need to use our own static buffer.
*/
if (*cpp) {
lsrp = *cpp;
lsrep = lsrp + *lenp;
ep = lsrp + *lenp;
} else {
*cpp = lsrp = lsr;
lsrep = lsrp + 44;
*cpp = lsrp = buf;
ep = lsrp + 1024;
}
cp = arg;
#ifdef INET6
if (ai->ai_family == AF_INET6) {
cmsg = inet6_rthdr_init(*cpp, IPV6_RTHDR_TYPE_0);
if (*cp != '@')
return -1;
*protop = IPPROTO_IPV6;
*optp = IPV6_PKTOPTIONS;
} else
#endif
{
/*
* Next, decide whether we have a loose source
* route or a strict source route, and fill in
@ -2966,13 +3048,20 @@ sourceroute(arg, cpp, lenp)
lsrp++; /* skip over length, we'll fill it in later */
*lsrp++ = 4;
#endif
*protop = IPPROTO_IP;
*optp = IP_OPTIONS;
}
cp++;
sin_addr.s_addr = 0;
memset(&hints, 0, sizeof(hints));
hints.ai_family = ai->ai_family;
hints.ai_socktype = SOCK_STREAM;
for (c = 0;;) {
if (c == ':')
if (
#ifdef INET6
ai->ai_family != AF_INET6 &&
#endif
c == ':')
cp2 = 0;
else for (cp2 = cp; (c = *cp2); cp2++) {
if (c == ',') {
@ -2981,7 +3070,11 @@ sourceroute(arg, cpp, lenp)
cp2++;
} else if (c == '@') {
*cp2++ = '\0';
} else if (c == ':') {
} else if (
#ifdef INET6
ai->ai_family != AF_INET6 &&
#endif
c == ':') {
*cp2++ = '\0';
} else
continue;
@ -2990,21 +3083,32 @@ sourceroute(arg, cpp, lenp)
if (!c)
cp2 = 0;
if ((tmp = inet_addr(cp)) != -1) {
sin_addr.s_addr = tmp;
} else if ((host = gethostbyname(cp))) {
#if defined(h_addr)
memmove((caddr_t)&sin_addr,
host->h_addr_list[0], host->h_length);
#else
memmove((caddr_t)&sin_addr, host->h_addr, host->h_length);
#endif
} else {
hints.ai_flags = AI_NUMERICHOST;
error = getaddrinfo(cp, NULL, &hints, &res);
if (error == EAI_NONAME) {
hints.ai_flags = 0;
error = getaddrinfo(cp, NULL, &hints, &res);
}
if (error != 0) {
fprintf(stderr, "%s: %s\n", cp, gai_strerror(error));
if (error == EAI_SYSTEM)
fprintf(stderr, "%s: %s\n", cp,
strerror(errno));
*cpp = cp;
return(0);
}
memmove(lsrp, (char *)&sin_addr, 4);
#ifdef INET6
if (res->ai_family == AF_INET6) {
sin6 = (struct sockaddr_in6 *)res->ai_addr;
inet6_rthdr_add(cmsg, &sin6->sin6_addr,
IPV6_RTHDR_LOOSE);
} else
#endif
{
sin = (struct sockaddr_in *)res->ai_addr;
memcpy(lsrp, (char *)&sin->sin_addr, 4);
lsrp += 4;
}
if (cp2)
cp = cp2;
else
@ -3012,9 +3116,27 @@ sourceroute(arg, cpp, lenp)
/*
* Check to make sure there is space for next address
*/
if (lsrp + 4 > lsrep)
#ifdef INET6
if (res->ai_family == AF_INET6) {
if (((char *)cmsg +
sizeof(struct cmsghdr) +
sizeof(struct ip6_rthdr) +
((inet6_rthdr_segments(cmsg) + 1) *
sizeof(struct in6_addr))) > ep)
return((unsigned long)-1);
} else
#endif
if (lsrp + 4 > ep)
return((unsigned long)-1);
freeaddrinfo(res);
}
#ifdef INET6
if (res->ai_family == AF_INET6) {
inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
*lenp = cmsg->cmsg_len;
} else
#endif
{
#ifndef sysV88
if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
*cpp = 0;
@ -3033,6 +3155,10 @@ sourceroute(arg, cpp, lenp)
*lenp = sizeof(ipopt);
*cpp = (char *) &ipopt;
#endif
return(sin_addr.s_addr);
}
freeaddrinfo(res);
return 1;
}
#endif

View File

@ -31,6 +31,7 @@
* SUCH DAMAGE.
*
* @(#)externs.h 8.3 (Berkeley) 5/30/95
* $FreeBSD$
*/
#ifndef BSD
@ -87,6 +88,14 @@ typedef unsigned char cc_t;
#include <strings.h>
#endif
#if defined(IPSEC)
#include <netinet6/ipsec.h>
#if defined(IPSEC_POLICY_IPSEC)
extern char *ipsec_policy_in;
extern char *ipsec_policy_out;
#endif
#endif
#ifndef _POSIX_VDISABLE
# ifdef sun
# include <sys/param.h> /* pick up VDISABLE definition, mayby */
@ -116,6 +125,7 @@ extern int
autologin, /* Autologin enabled */
skiprc, /* Don't process the ~/.telnetrc file */
eight, /* use eight bit mode (binary in and/or out */
family, /* address family of peer */
flushout, /* flush output */
connected, /* Are we connected to the other side? */
globalmode, /* Mode tty should be in */

View File

@ -29,6 +29,8 @@
* 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$
*/
#ifndef lint
@ -42,6 +44,7 @@ static const char sccsid[] = "@(#)main.c 8.3 (Berkeley) 5/30/95";
#endif /* not lint */
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include "ring.h"
@ -70,6 +73,13 @@ void init_telnet(void);
void init_sys(void);
void init_3270(void);
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
char *ipsec_policy_in = NULL;
char *ipsec_policy_out = NULL;
#endif
int family = AF_UNSPEC;
/*
* Initialize variables.
*/
@ -95,10 +105,10 @@ usage()
fprintf(stderr, "Usage: %s %s%s%s%s\n",
prompt,
#ifdef AUTHENTICATION
"[-8] [-E] [-K] [-L] [-N] [-S tos] [-X atype] [-a] [-c] [-d]",
"[-4] [-6] [-8] [-E] [-K] [-L] [-N] [-S tos] [-X atype] [-a] [-c] [-d]",
"\n\t[-e char] [-k realm] [-l user] [-f/-F] [-n tracefile] ",
#else
"[-8] [-E] [-L] [-N] [-S tos] [-a] [-c] [-d] [-e char] [-l user]",
"[-4] [-6] [-8] [-E] [-L] [-N] [-S tos] [-a] [-c] [-d] [-e char] [-l user]",
"\n\t[-n tracefile] ",
#endif
#if defined(TN3270) && defined(unix)
@ -112,6 +122,9 @@ usage()
#else
"[-r] [-s src_addr] ",
#endif
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
"[-P policy]"
#endif
#ifdef ENCRYPTION
"[-x] [host-name [port]]"
#else /* ENCRYPTION */
@ -156,8 +169,24 @@ main(argc, argv)
rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE;
autologin = -1;
while ((ch = getopt(argc, argv, "8EKLNS:X:acde:fFk:l:n:rs:t:x")) != EOF) {
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
#define IPSECOPT "P:"
#else
#define IPSECOPT
#endif
while ((ch = getopt(argc, argv,
"468EKLNS:X:acde:fFk:l:n:rs:t:x" IPSECOPT)) != -1)
#undef IPSECOPT
{
switch(ch) {
case '4':
family = AF_INET;
break;
#ifdef INET6
case '6':
family = AF_INET6;
break;
#endif
case '8':
eight = 3; /* binary output and input */
break;
@ -299,6 +328,16 @@ main(argc, argv)
prompt);
#endif /* ENCRYPTION */
break;
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
case 'P':
if (!strncmp("in", optarg, 2))
ipsec_policy_in = strdup(optarg);
else if (!strncmp("out", optarg, 3))
ipsec_policy_out = strdup(optarg);
else
usage();
break;
#endif
case '?':
default:
usage();

View File

@ -30,8 +30,9 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)telnet.1 8.6 (Berkeley) 6/1/94
.\" $FreeBSD$
.\"
.Dd June 1, 1994
.Dd January 27, 2000
.Dt TELNET 1
.Os BSD 4.2
.Sh NAME
@ -549,9 +550,10 @@ will attempt to contact a
.Tn TELNET
server at the default port.
The host specification may be either a host name (see
.Xr hosts 5 )
or an Internet address specified in the \*(Lqdot notation\*(Rq (see
.Xr inet 3 ) .
.Xr hosts 5 ) ,
an Internet address specified in the \*(Lqdot notation\*(Rq (see
.Xr inet 3 ) ,
or IPv6 host name or IPv6 coloned-hexadecimal addreess.
The
.Op Fl l
option may be used to specify the user name
@ -1367,6 +1369,8 @@ The
.Nm Telnet
command appeared in
.Bx 4.2 .
.Pp
IPv6 support was added by WIDE/KAME project.
.Sh NOTES
.Pp
On some remote systems, echo has to be turned off manually when in

View File

@ -30,8 +30,9 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)telnetd.8 8.4 (Berkeley) 6/1/94
.\" $FreeBSD$
.\"
.Dd June 1, 1994
.Dd January 27, 2000
.Dt TELNETD 8
.Os BSD 4.2
.Sh NAME
@ -610,3 +611,5 @@ never sends
.Tn TELNET
.Dv IAC GA
(go ahead) commands.
.Sh HISTORY
IPv6 support was added by WIDE/KAME project.

View File

@ -70,6 +70,12 @@ static const char rcsid[] =
#include <sys/secparm.h>
#include <sys/usrv.h>
# endif /* SO_SEC_MULTI */
/* wrapper for KAME-special getnameinfo() */
#ifndef NI_WITHSCOPEID
#define NI_WITHSCOPEID 0
#endif
int secflag;
char tty_dev[16];
struct secdev dv;
@ -128,7 +134,7 @@ char ptyibuf2[BUFSIZ];
# include <termcap.h>
int readstream(int p, char *ibuf, int bufsize);
void doit(struct sockaddr_in *who);
void doit(struct sockaddr *who);
int terminaltypeok(char *s);
void startslave(char *host, int autologin, char *autoname);
@ -145,7 +151,7 @@ int debug = 0;
int keepalive = 1;
char *altlogin;
void doit __P((struct sockaddr_in *));
void doit __P((struct sockaddr *));
int terminaltypeok __P((char *));
void startslave __P((char *, int, char *));
extern void usage P((void));
@ -157,6 +163,7 @@ extern void usage P((void));
*/
char valid_opts[] = {
'd', ':', 'h', 'k', 'n', 'p', ':', 'S', ':', 'u', ':', 'U',
'4', '6',
#ifdef AUTHENTICATION
'a', ':', 'X', ':',
#endif
@ -184,11 +191,13 @@ char valid_opts[] = {
'\0'
};
int
int family = AF_INET;
int
main(argc, argv)
char *argv[];
{
struct sockaddr_in from;
struct sockaddr_storage from;
int on = 1, fromlen;
register int ch;
#if defined(IPPROTO_IP) && defined(IP_TOS)
@ -406,6 +415,16 @@ main(argc, argv)
break;
#endif /* AUTHENTICATION */
case '4':
family = AF_INET;
break;
#ifdef INET6
case '6':
family = AF_INET6;
break;
#endif
default:
warnx("%c: unknown option", ch);
/* FALLTHROUGH */
@ -419,43 +438,41 @@ main(argc, argv)
argv += optind;
if (debug) {
int s, ns, foo;
struct servent *sp;
static struct sockaddr_in sin = { AF_INET };
int s, ns, foo, error;
char *service = "telnet";
struct addrinfo hints, *res;
if (argc > 1) {
usage();
/* NOT REACHED */
} else if (argc == 1) {
if ((sp = getservbyname(*argv, "tcp"))) {
sin.sin_port = sp->s_port;
} else {
sin.sin_port = atoi(*argv);
if ((int)sin.sin_port <= 0) {
warnx("%s: bad port #", *argv);
usage();
/* NOT REACHED */
}
sin.sin_port = htons((u_short)sin.sin_port);
}
} else {
sp = getservbyname("telnet", "tcp");
if (sp == 0)
errx(1, "tcp/telnet: unknown service");
sin.sin_port = sp->s_port;
} else if (argc == 1)
service = *argv;
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) {
errx(1, "tcp/%s: %s\n", service, gai_strerror(error));
if (error == EAI_SYSTEM)
errx(1, "tcp/%s: %s\n", service, strerror(errno));
usage();
}
s = socket(AF_INET, SOCK_STREAM, 0);
s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (s < 0)
err(1, "socket");
(void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on));
if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0)
if (bind(s, res->ai_addr, res->ai_addrlen) < 0)
err(1, "bind");
if (listen(s, 1) < 0)
err(1, "listen");
foo = sizeof sin;
ns = accept(s, (struct sockaddr *)&sin, &foo);
foo = res->ai_addrlen;
ns = accept(s, res->ai_addr, &foo);
if (ns < 0)
err(1, "accept");
(void) dup2(ns, 0);
@ -537,7 +554,7 @@ main(argc, argv)
}
#if defined(IPPROTO_IP) && defined(IP_TOS)
{
if (from.ss_family == AF_INET) {
# if defined(HAS_GETTOS)
struct tosent *tp;
if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
@ -553,7 +570,7 @@ main(argc, argv)
}
#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
net = 0;
doit(&from);
doit((struct sockaddr *)&from);
/* NOTREACHED */
return(0);
} /* end of main */
@ -821,8 +838,9 @@ char user_name[256];
*/
void
doit(who)
struct sockaddr_in *who;
struct sockaddr *who;
{
int err;
int ptynum;
/*
@ -865,16 +883,18 @@ doit(who)
#endif /* _SC_CRAY_SECURE_SYS */
/* get name of connected client */
if (realhostname(remote_hostname, sizeof(remote_hostname) - 1,
&who->sin_addr) == HOSTNAME_INVALIDADDR && registerd_host_only)
if (realhostname_sa(remote_hostname, sizeof(remote_hostname) - 1,
who, who->sa_len) == HOSTNAME_INVALIDADDR && registerd_host_only)
fatal(net, "Couldn't resolve your address into a host name.\r\n\
Please contact your net administrator");
remote_hostname[sizeof(remote_hostname) - 1] = '\0';
trimdomain(remote_hostname, UT_HOSTSIZE);
if (!isdigit(remote_hostname[0]) && strlen(remote_hostname) > utmp_len)
strncpy(remote_hostname, inet_ntoa(who->sin_addr),
sizeof(remote_hostname) - 1);
err = getnameinfo(who, who->sa_len, remote_hostname,
sizeof(remote_hostname), NULL, 0,
NI_NUMERICHOST|NI_WITHSCOPEID);
/* XXX: do 'err' check */
(void) gethostname(host_name, sizeof(host_name) - 1);
host_name[sizeof(host_name) - 1] = '\0';

View File

@ -29,6 +29,8 @@
* 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$
*/
#ifndef lint
@ -83,6 +85,7 @@ static const char sccsid[] = "@(#)commands.c 8.4 (Berkeley) 5/30/95";
# endif /* vax */
#endif /* !defined(CRAY) && !defined(sysV88) */
#include <netinet/ip.h>
#include <netinet/ip6.h>
#ifndef MAXHOSTNAMELEN
@ -2270,27 +2273,76 @@ ayt_status()
}
#endif
unsigned long inet_addr();
static const char *
sockaddr_ntop(sa)
struct sockaddr *sa;
{
void *addr;
static char addrbuf[INET6_ADDRSTRLEN];
switch (sa->sa_family) {
case AF_INET:
addr = &((struct sockaddr_in *)sa)->sin_addr;
break;
#ifdef INET6
case AF_INET6:
addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
break;
#endif
default:
return NULL;
}
inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf));
return addrbuf;
}
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
static int
setpolicy(net, res, policy)
int net;
struct addrinfo *res;
char *policy;
{
char *buf;
int level;
int optname;
if (policy == NULL)
return 0;
buf = ipsec_set_policy(policy, strlen(policy));
if (buf == NULL) {
printf("%s\n", ipsec_strerror());
return -1;
}
level = res->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
optname = res->ai_family == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY;
if (setsockopt(net, level, optname, buf, ipsec_get_policylen(buf)) < 0){
perror("setsockopt");
return -1;
}
free(buf);
}
#endif
int
tn(argc, argv)
int argc;
char *argv[];
{
register struct hostent *host = 0;
struct sockaddr_in sin, src_sin;
struct servent *sp = 0;
unsigned long temp;
extern char *inet_ntoa();
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
struct sockaddr_storage ss, src_ss;
char *srp = 0, *strrchr();
unsigned long sourceroute(), srlen;
#endif
int proto, opt;
int sourceroute(), srlen;
int srcroute = 0, result;
char *cmd, *hostp = 0, *portp = 0, *user = 0;
char *src_addr = NULL;
struct addrinfo hints, *res;
int error = 0;
/* clear the socket address prior to use */
memset((char *)&sin, 0, sizeof(sin));
memset((char *)&ss, 0, sizeof(ss));
if (connected) {
printf("?Already connected to %s\n", hostname);
@ -2350,126 +2402,106 @@ tn(argc, argv)
goto usage;
if (src_addr != NULL) {
bzero((char *)&src_sin, sizeof(src_sin));
src_sin.sin_family = AF_INET;
if (!inet_aton(src_addr, &src_sin.sin_addr)) {
host = gethostbyname2(src_addr, AF_INET);
if (host == NULL) {
herror(src_addr);
return 0;
}
if (host->h_length != sizeof(src_sin.sin_addr)) {
fprintf(stderr, "telnet: gethostbyname2: invalid address\n");
return 0;
}
memcpy((void *)&src_sin.sin_addr, (void *)host->h_addr_list[0],
sizeof(src_sin.sin_addr));
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(src_addr, 0, &hints, &res);
if (error == EAI_NONAME) {
hints.ai_flags = 0;
error = getaddrinfo(src_addr, 0, &hints, &res);
}
if (error != 0) {
fprintf(stderr, "%s: %s\n", src_addr, gai_strerror(error));
if (error == EAI_SYSTEM)
fprintf(stderr, "%s: %s\n", src_addr, strerror(errno));
return 0;
}
memcpy((void *)&src_ss, (void *)res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
}
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
if (hostp[0] == '@' || hostp[0] == '!') {
if ((hostname = strrchr(hostp, ':')) == NULL)
if (
#ifdef INET6
family == AF_INET6 ||
#endif
(hostname = strrchr(hostp, ':')) == NULL)
hostname = strrchr(hostp, '@');
hostname++;
srp = 0;
temp = sourceroute(hostp, &srp, &srlen);
if (temp == 0) {
herror(srp);
srcroute = 1;
} else
hostname = hostp;
if (!portp) {
telnetport = 1;
portp = "telnet";
} else if (*portp == '-') {
portp++;
telnetport = 1;
} else
telnetport = 0;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(hostname, portp, &hints, &res);
if (error == 0) {
int gni_err = 1;
if (doaddrlookup)
gni_err = getnameinfo(res->ai_addr, res->ai_addr->sa_len,
_hostname, sizeof(_hostname) - 1, NULL, 0,
0);
if (gni_err != 0)
(void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
_hostname[sizeof(_hostname)-1] = '\0';
hostname = _hostname;
} else if (error == EAI_NONAME) {
hints.ai_flags = AI_CANONNAME;
error = getaddrinfo(hostname, portp, &hints, &res);
if (error != 0) {
fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error));
if (error == EAI_SYSTEM)
fprintf(stderr, "%s: %s\n", hostname, strerror(errno));
setuid(getuid());
return 0;
} else if (temp == -1) {
}
memcpy((void *)&ss, (void *)res->ai_addr, res->ai_addrlen);
if (srcroute != 0)
(void) strncpy(_hostname, hostname, sizeof(_hostname) - 1);
else if (res->ai_canonname != NULL)
strcpy(_hostname, res->ai_canonname);
else
(void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
_hostname[sizeof(_hostname)-1] = '\0';
hostname = _hostname;
}
if (srcroute != 0) {
srp = 0;
result = sourceroute(res, hostp, &srp, &srlen, &proto, &opt);
if (result == 0) {
setuid(getuid());
freeaddrinfo(res);
return 0;
} else if (result == -1) {
printf("Bad source route option: %s\n", hostp);
setuid(getuid());
freeaddrinfo(res);
return 0;
} else {
sin.sin_addr.s_addr = temp;
sin.sin_family = AF_INET;
}
} else {
#endif
temp = inet_addr(hostp);
if (temp != INADDR_NONE) {
sin.sin_addr.s_addr = temp;
sin.sin_family = AF_INET;
if (doaddrlookup)
host = gethostbyaddr((char *)&temp, sizeof(temp), AF_INET);
if (host)
(void) strncpy(_hostname, host->h_name, sizeof(_hostname));
else
(void) strncpy(_hostname, hostp, sizeof(_hostname));
_hostname[sizeof(_hostname)-1] = '\0';
hostname = _hostname;
} else {
host = gethostbyname(hostp);
if (host) {
sin.sin_family = host->h_addrtype;
#if defined(h_addr) /* In 4.3, this is a #define */
memmove((caddr_t)&sin.sin_addr,
host->h_addr_list[0], host->h_length);
#else /* defined(h_addr) */
memmove((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
#endif /* defined(h_addr) */
strncpy(_hostname, host->h_name, sizeof(_hostname));
_hostname[sizeof(_hostname)-1] = '\0';
hostname = _hostname;
} else {
herror(hostp);
setuid(getuid());
return 0;
}
}
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
}
#endif
if (portp) {
if (*portp == '-') {
portp++;
telnetport = 1;
} else
telnetport = 0;
sin.sin_port = atoi(portp);
if (sin.sin_port == 0) {
sp = getservbyname(portp, "tcp");
if (sp)
sin.sin_port = sp->s_port;
else {
printf("%s: bad port number\n", portp);
setuid(getuid());
return 0;
}
} else {
#if !defined(htons)
u_short htons P((unsigned short));
#endif /* !defined(htons) */
sin.sin_port = htons(sin.sin_port);
}
} else {
if (sp == 0) {
sp = getservbyname("telnet", "tcp");
if (sp == 0) {
fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
setuid(getuid());
return 0;
}
sin.sin_port = sp->s_port;
}
telnetport = 1;
}
printf("Trying %s...\n", inet_ntoa(sin.sin_addr));
printf("Trying %s...\n", sockaddr_ntop(res->ai_addr));
do {
net = socket(AF_INET, SOCK_STREAM, 0);
net = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
setuid(getuid());
if (net < 0) {
perror("telnet: socket");
return 0;
}
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
perror("setsockopt (IP_OPTIONS)");
#endif
if (srp && setsockopt(net, proto, opt, (char *)srp, srlen) < 0)
perror("setsockopt (source route)");
#if defined(IPPROTO_IP) && defined(IP_TOS)
{
if (res->ai_family == PF_INET) {
# if defined(HAS_GETTOS)
struct tosent *tp;
if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
@ -2490,28 +2522,31 @@ tn(argc, argv)
}
if (src_addr != NULL) {
if (bind(net, (struct sockaddr *)&src_sin, sizeof(src_sin)) == -1) {
if (bind(net, (struct sockaddr *)&src_ss,
((struct sockaddr *)&src_ss)->sa_len) == -1) {
perror("bind");
return 0;
}
}
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
if (setpolicy(net, res, ipsec_policy_in) < 0)
return 0;
if (setpolicy(net, res, ipsec_policy_out) < 0)
return 0;
#endif
if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
#if defined(h_addr) /* In 4.3, this is a #define */
if (host && host->h_addr_list[1]) {
if (connect(net, res->ai_addr, res->ai_addrlen) < 0) {
if (res->ai_next) {
int oerrno = errno;
fprintf(stderr, "telnet: connect to address %s: ",
inet_ntoa(sin.sin_addr));
sockaddr_ntop(res->ai_addr));
errno = oerrno;
perror((char *)0);
host->h_addr_list++;
memmove((caddr_t)&sin.sin_addr,
host->h_addr_list[0], host->h_length);
res = res->ai_next;
(void) NetClose(net);
continue;
}
#endif /* defined(h_addr) */
perror("telnet: Unable to connect to remote host");
return 0;
}
@ -2520,6 +2555,7 @@ tn(argc, argv)
auth_encrypt_connect(connected);
#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
} while (connected == 0);
freeaddrinfo(res);
cmdrc(hostp, hostname);
if (autologin && user == NULL) {
struct passwd *pw;
@ -2861,8 +2897,6 @@ cmdrc(m1, m2)
fclose(rcfile);
}
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
/*
* Source route is handed in as
* [!]@hop1@hop2...[@|:]dst
@ -2876,6 +2910,10 @@ cmdrc(m1, m2)
* be the address to connect() to.
*
* Arguments:
*
* res: ponter to addrinfo structure which contains sockaddr to
* the host to connect to.
*
* arg: pointer to route list to decipher
*
* cpp: If *cpp is not equal to NULL, this is a
@ -2885,9 +2923,18 @@ cmdrc(m1, m2)
* lenp: pointer to an integer that contains the
* length of *cpp if *cpp != NULL.
*
* protop: pointer to an integer that should be filled in with
* appropriate protocol for setsockopt, as socket
* protocol family.
*
* optp: pointer to an integer that should be filled in with
* appropriate option for setsockopt, as socket protocol
* family.
*
* Return values:
*
* Returns the address of the host to connect to. If the
* If the return value is 1, then all operations are
* successful. If the
* return value is -1, there was a syntax error in the
* option, either unknown characters, or too many hosts.
* If the return value is 0, one of the hostnames in the
@ -2901,21 +2948,32 @@ cmdrc(m1, m2)
* *lenp: This will be filled in with how long the option
* pointed to by *cpp is.
*
* *protop: This will be filled in with appropriate protocol for
* setsockopt, as socket protocol family.
*
* *optp: This will be filled in with appropriate option for
* setsockopt, as socket protocol family.
*/
unsigned long
sourceroute(arg, cpp, lenp)
int
sourceroute(ai, arg, cpp, lenp, protop, optp)
struct addrinfo *ai;
char *arg;
char **cpp;
int *lenp;
int *protop;
int *optp;
{
static char lsr[44];
static char buf[1024]; /*XXX*/
struct cmsghdr *cmsg;
#ifdef sysV88
static IOPTN ipopt;
#endif
char *cp, *cp2, *lsrp, *lsrep;
char *cp, *cp2, *lsrp, *ep;
register int tmp;
struct in_addr sin_addr;
register struct hostent *host = 0;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
struct addrinfo hints, *res;
int error;
register char c;
/*
@ -2924,22 +2982,46 @@ sourceroute(arg, cpp, lenp)
*/
if (cpp == NULL || lenp == NULL)
return((unsigned long)-1);
if (*cpp != NULL && *lenp < 7)
return((unsigned long)-1);
if (*cpp != NULL) {
switch (res->ai_family) {
case AF_INET:
if (*lenp < 7)
return((unsigned long)-1);
break;
#ifdef INET6
case AF_INET6:
if (*lenp < (sizeof(struct cmsghdr) +
sizeof(struct ip6_rthdr) +
sizeof(struct in6_addr)))
return((unsigned long)-1);
break;
#endif
}
}
/*
* Decide whether we have a buffer passed to us,
* or if we need to use our own static buffer.
*/
if (*cpp) {
lsrp = *cpp;
lsrep = lsrp + *lenp;
ep = lsrp + *lenp;
} else {
*cpp = lsrp = lsr;
lsrep = lsrp + 44;
*cpp = lsrp = buf;
ep = lsrp + 1024;
}
cp = arg;
#ifdef INET6
if (ai->ai_family == AF_INET6) {
cmsg = inet6_rthdr_init(*cpp, IPV6_RTHDR_TYPE_0);
if (*cp != '@')
return -1;
*protop = IPPROTO_IPV6;
*optp = IPV6_PKTOPTIONS;
} else
#endif
{
/*
* Next, decide whether we have a loose source
* route or a strict source route, and fill in
@ -2966,13 +3048,20 @@ sourceroute(arg, cpp, lenp)
lsrp++; /* skip over length, we'll fill it in later */
*lsrp++ = 4;
#endif
*protop = IPPROTO_IP;
*optp = IP_OPTIONS;
}
cp++;
sin_addr.s_addr = 0;
memset(&hints, 0, sizeof(hints));
hints.ai_family = ai->ai_family;
hints.ai_socktype = SOCK_STREAM;
for (c = 0;;) {
if (c == ':')
if (
#ifdef INET6
ai->ai_family != AF_INET6 &&
#endif
c == ':')
cp2 = 0;
else for (cp2 = cp; (c = *cp2); cp2++) {
if (c == ',') {
@ -2981,7 +3070,11 @@ sourceroute(arg, cpp, lenp)
cp2++;
} else if (c == '@') {
*cp2++ = '\0';
} else if (c == ':') {
} else if (
#ifdef INET6
ai->ai_family != AF_INET6 &&
#endif
c == ':') {
*cp2++ = '\0';
} else
continue;
@ -2990,21 +3083,32 @@ sourceroute(arg, cpp, lenp)
if (!c)
cp2 = 0;
if ((tmp = inet_addr(cp)) != -1) {
sin_addr.s_addr = tmp;
} else if ((host = gethostbyname(cp))) {
#if defined(h_addr)
memmove((caddr_t)&sin_addr,
host->h_addr_list[0], host->h_length);
#else
memmove((caddr_t)&sin_addr, host->h_addr, host->h_length);
#endif
} else {
hints.ai_flags = AI_NUMERICHOST;
error = getaddrinfo(cp, NULL, &hints, &res);
if (error == EAI_NONAME) {
hints.ai_flags = 0;
error = getaddrinfo(cp, NULL, &hints, &res);
}
if (error != 0) {
fprintf(stderr, "%s: %s\n", cp, gai_strerror(error));
if (error == EAI_SYSTEM)
fprintf(stderr, "%s: %s\n", cp,
strerror(errno));
*cpp = cp;
return(0);
}
memmove(lsrp, (char *)&sin_addr, 4);
#ifdef INET6
if (res->ai_family == AF_INET6) {
sin6 = (struct sockaddr_in6 *)res->ai_addr;
inet6_rthdr_add(cmsg, &sin6->sin6_addr,
IPV6_RTHDR_LOOSE);
} else
#endif
{
sin = (struct sockaddr_in *)res->ai_addr;
memcpy(lsrp, (char *)&sin->sin_addr, 4);
lsrp += 4;
}
if (cp2)
cp = cp2;
else
@ -3012,9 +3116,27 @@ sourceroute(arg, cpp, lenp)
/*
* Check to make sure there is space for next address
*/
if (lsrp + 4 > lsrep)
#ifdef INET6
if (res->ai_family == AF_INET6) {
if (((char *)cmsg +
sizeof(struct cmsghdr) +
sizeof(struct ip6_rthdr) +
((inet6_rthdr_segments(cmsg) + 1) *
sizeof(struct in6_addr))) > ep)
return((unsigned long)-1);
} else
#endif
if (lsrp + 4 > ep)
return((unsigned long)-1);
freeaddrinfo(res);
}
#ifdef INET6
if (res->ai_family == AF_INET6) {
inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
*lenp = cmsg->cmsg_len;
} else
#endif
{
#ifndef sysV88
if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
*cpp = 0;
@ -3033,6 +3155,10 @@ sourceroute(arg, cpp, lenp)
*lenp = sizeof(ipopt);
*cpp = (char *) &ipopt;
#endif
return(sin_addr.s_addr);
}
freeaddrinfo(res);
return 1;
}
#endif

View File

@ -31,6 +31,7 @@
* SUCH DAMAGE.
*
* @(#)externs.h 8.3 (Berkeley) 5/30/95
* $FreeBSD$
*/
#ifndef BSD
@ -87,6 +88,14 @@ typedef unsigned char cc_t;
#include <strings.h>
#endif
#if defined(IPSEC)
#include <netinet6/ipsec.h>
#if defined(IPSEC_POLICY_IPSEC)
extern char *ipsec_policy_in;
extern char *ipsec_policy_out;
#endif
#endif
#ifndef _POSIX_VDISABLE
# ifdef sun
# include <sys/param.h> /* pick up VDISABLE definition, mayby */
@ -116,6 +125,7 @@ extern int
autologin, /* Autologin enabled */
skiprc, /* Don't process the ~/.telnetrc file */
eight, /* use eight bit mode (binary in and/or out */
family, /* address family of peer */
flushout, /* flush output */
connected, /* Are we connected to the other side? */
globalmode, /* Mode tty should be in */

View File

@ -29,6 +29,8 @@
* 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$
*/
#ifndef lint
@ -42,6 +44,7 @@ static const char sccsid[] = "@(#)main.c 8.3 (Berkeley) 5/30/95";
#endif /* not lint */
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include "ring.h"
@ -70,6 +73,13 @@ void init_telnet(void);
void init_sys(void);
void init_3270(void);
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
char *ipsec_policy_in = NULL;
char *ipsec_policy_out = NULL;
#endif
int family = AF_UNSPEC;
/*
* Initialize variables.
*/
@ -95,10 +105,10 @@ usage()
fprintf(stderr, "Usage: %s %s%s%s%s\n",
prompt,
#ifdef AUTHENTICATION
"[-8] [-E] [-K] [-L] [-N] [-S tos] [-X atype] [-a] [-c] [-d]",
"[-4] [-6] [-8] [-E] [-K] [-L] [-N] [-S tos] [-X atype] [-a] [-c] [-d]",
"\n\t[-e char] [-k realm] [-l user] [-f/-F] [-n tracefile] ",
#else
"[-8] [-E] [-L] [-N] [-S tos] [-a] [-c] [-d] [-e char] [-l user]",
"[-4] [-6] [-8] [-E] [-L] [-N] [-S tos] [-a] [-c] [-d] [-e char] [-l user]",
"\n\t[-n tracefile] ",
#endif
#if defined(TN3270) && defined(unix)
@ -112,6 +122,9 @@ usage()
#else
"[-r] [-s src_addr] ",
#endif
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
"[-P policy]"
#endif
#ifdef ENCRYPTION
"[-x] [host-name [port]]"
#else /* ENCRYPTION */
@ -156,8 +169,24 @@ main(argc, argv)
rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE;
autologin = -1;
while ((ch = getopt(argc, argv, "8EKLNS:X:acde:fFk:l:n:rs:t:x")) != EOF) {
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
#define IPSECOPT "P:"
#else
#define IPSECOPT
#endif
while ((ch = getopt(argc, argv,
"468EKLNS:X:acde:fFk:l:n:rs:t:x" IPSECOPT)) != -1)
#undef IPSECOPT
{
switch(ch) {
case '4':
family = AF_INET;
break;
#ifdef INET6
case '6':
family = AF_INET6;
break;
#endif
case '8':
eight = 3; /* binary output and input */
break;
@ -299,6 +328,16 @@ main(argc, argv)
prompt);
#endif /* ENCRYPTION */
break;
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
case 'P':
if (!strncmp("in", optarg, 2))
ipsec_policy_in = strdup(optarg);
else if (!strncmp("out", optarg, 3))
ipsec_policy_out = strdup(optarg);
else
usage();
break;
#endif
case '?':
default:
usage();

View File

@ -30,8 +30,9 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)telnet.1 8.6 (Berkeley) 6/1/94
.\" $FreeBSD$
.\"
.Dd June 1, 1994
.Dd January 27, 2000
.Dt TELNET 1
.Os BSD 4.2
.Sh NAME
@ -549,9 +550,10 @@ will attempt to contact a
.Tn TELNET
server at the default port.
The host specification may be either a host name (see
.Xr hosts 5 )
or an Internet address specified in the \*(Lqdot notation\*(Rq (see
.Xr inet 3 ) .
.Xr hosts 5 ) ,
an Internet address specified in the \*(Lqdot notation\*(Rq (see
.Xr inet 3 ) ,
or IPv6 host name or IPv6 coloned-hexadecimal addreess.
The
.Op Fl l
option may be used to specify the user name
@ -1367,6 +1369,8 @@ The
.Nm Telnet
command appeared in
.Bx 4.2 .
.Pp
IPv6 support was added by WIDE/KAME project.
.Sh NOTES
.Pp
On some remote systems, echo has to be turned off manually when in

View File

@ -30,8 +30,9 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)telnetd.8 8.4 (Berkeley) 6/1/94
.\" $FreeBSD$
.\"
.Dd June 1, 1994
.Dd January 27, 2000
.Dt TELNETD 8
.Os BSD 4.2
.Sh NAME
@ -610,3 +611,5 @@ never sends
.Tn TELNET
.Dv IAC GA
(go ahead) commands.
.Sh HISTORY
IPv6 support was added by WIDE/KAME project.

View File

@ -70,6 +70,12 @@ static const char rcsid[] =
#include <sys/secparm.h>
#include <sys/usrv.h>
# endif /* SO_SEC_MULTI */
/* wrapper for KAME-special getnameinfo() */
#ifndef NI_WITHSCOPEID
#define NI_WITHSCOPEID 0
#endif
int secflag;
char tty_dev[16];
struct secdev dv;
@ -128,7 +134,7 @@ char ptyibuf2[BUFSIZ];
# include <termcap.h>
int readstream(int p, char *ibuf, int bufsize);
void doit(struct sockaddr_in *who);
void doit(struct sockaddr *who);
int terminaltypeok(char *s);
void startslave(char *host, int autologin, char *autoname);
@ -145,7 +151,7 @@ int debug = 0;
int keepalive = 1;
char *altlogin;
void doit __P((struct sockaddr_in *));
void doit __P((struct sockaddr *));
int terminaltypeok __P((char *));
void startslave __P((char *, int, char *));
extern void usage P((void));
@ -157,6 +163,7 @@ extern void usage P((void));
*/
char valid_opts[] = {
'd', ':', 'h', 'k', 'n', 'p', ':', 'S', ':', 'u', ':', 'U',
'4', '6',
#ifdef AUTHENTICATION
'a', ':', 'X', ':',
#endif
@ -184,11 +191,13 @@ char valid_opts[] = {
'\0'
};
int
int family = AF_INET;
int
main(argc, argv)
char *argv[];
{
struct sockaddr_in from;
struct sockaddr_storage from;
int on = 1, fromlen;
register int ch;
#if defined(IPPROTO_IP) && defined(IP_TOS)
@ -406,6 +415,16 @@ main(argc, argv)
break;
#endif /* AUTHENTICATION */
case '4':
family = AF_INET;
break;
#ifdef INET6
case '6':
family = AF_INET6;
break;
#endif
default:
warnx("%c: unknown option", ch);
/* FALLTHROUGH */
@ -419,43 +438,41 @@ main(argc, argv)
argv += optind;
if (debug) {
int s, ns, foo;
struct servent *sp;
static struct sockaddr_in sin = { AF_INET };
int s, ns, foo, error;
char *service = "telnet";
struct addrinfo hints, *res;
if (argc > 1) {
usage();
/* NOT REACHED */
} else if (argc == 1) {
if ((sp = getservbyname(*argv, "tcp"))) {
sin.sin_port = sp->s_port;
} else {
sin.sin_port = atoi(*argv);
if ((int)sin.sin_port <= 0) {
warnx("%s: bad port #", *argv);
usage();
/* NOT REACHED */
}
sin.sin_port = htons((u_short)sin.sin_port);
}
} else {
sp = getservbyname("telnet", "tcp");
if (sp == 0)
errx(1, "tcp/telnet: unknown service");
sin.sin_port = sp->s_port;
} else if (argc == 1)
service = *argv;
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) {
errx(1, "tcp/%s: %s\n", service, gai_strerror(error));
if (error == EAI_SYSTEM)
errx(1, "tcp/%s: %s\n", service, strerror(errno));
usage();
}
s = socket(AF_INET, SOCK_STREAM, 0);
s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (s < 0)
err(1, "socket");
(void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on));
if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0)
if (bind(s, res->ai_addr, res->ai_addrlen) < 0)
err(1, "bind");
if (listen(s, 1) < 0)
err(1, "listen");
foo = sizeof sin;
ns = accept(s, (struct sockaddr *)&sin, &foo);
foo = res->ai_addrlen;
ns = accept(s, res->ai_addr, &foo);
if (ns < 0)
err(1, "accept");
(void) dup2(ns, 0);
@ -537,7 +554,7 @@ main(argc, argv)
}
#if defined(IPPROTO_IP) && defined(IP_TOS)
{
if (from.ss_family == AF_INET) {
# if defined(HAS_GETTOS)
struct tosent *tp;
if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
@ -553,7 +570,7 @@ main(argc, argv)
}
#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
net = 0;
doit(&from);
doit((struct sockaddr *)&from);
/* NOTREACHED */
return(0);
} /* end of main */
@ -821,8 +838,9 @@ char user_name[256];
*/
void
doit(who)
struct sockaddr_in *who;
struct sockaddr *who;
{
int err;
int ptynum;
/*
@ -865,16 +883,18 @@ doit(who)
#endif /* _SC_CRAY_SECURE_SYS */
/* get name of connected client */
if (realhostname(remote_hostname, sizeof(remote_hostname) - 1,
&who->sin_addr) == HOSTNAME_INVALIDADDR && registerd_host_only)
if (realhostname_sa(remote_hostname, sizeof(remote_hostname) - 1,
who, who->sa_len) == HOSTNAME_INVALIDADDR && registerd_host_only)
fatal(net, "Couldn't resolve your address into a host name.\r\n\
Please contact your net administrator");
remote_hostname[sizeof(remote_hostname) - 1] = '\0';
trimdomain(remote_hostname, UT_HOSTSIZE);
if (!isdigit(remote_hostname[0]) && strlen(remote_hostname) > utmp_len)
strncpy(remote_hostname, inet_ntoa(who->sin_addr),
sizeof(remote_hostname) - 1);
err = getnameinfo(who, who->sa_len, remote_hostname,
sizeof(remote_hostname), NULL, 0,
NI_NUMERICHOST|NI_WITHSCOPEID);
/* XXX: do 'err' check */
(void) gethostname(host_name, sizeof(host_name) - 1);
host_name[sizeof(host_name) - 1] = '\0';

View File

@ -8,7 +8,7 @@ MAN8= telnetd.8
CFLAGS+= -DLINEMODE -DUSE_TERMIO -DDIAGNOSTICS -DOLD_ENVIRON \
-DENV_HACK -DAUTHENTICATION -DENCRYPTION \
-I${TELNETDIR}
-I${TELNETDIR} -DINET6
SRCS= global.c slc.c state.c sys_term.c telnetd.c \
termstat.c utility.c authenc.c

View File

@ -4,15 +4,15 @@ PROG= telnet
CFLAGS+= -DKLUDGELINEMODE -DUSE_TERMIO -DENV_HACK -DSKEY \
-DENCRYPTION -DAUTHENTICATION -DKRB4 \
-I${TELNETDIR}
-I${TELNETDIR} -DIPSEC -DINET6
SRCS= authenc.c commands.c main.c network.c ring.c sys_bsd.c \
telnet.c terminal.c tn3270.c utilities.c
DPADD= ${LIBTERMCAP} ${LIBTELNET} ${LIBDES} ${LIBKRB} ${LIBCRYPT} \
${LIBCOM_ERR}
${LIBCOM_ERR} ${LIBIPSEC}
LDADD= -ltermcap -L${TELNETOBJDIR} -ltelnet -ldes \
-L${KRBOBJDIR} -lkrb -lcrypt -lcom_err -lmp
-L${KRBOBJDIR} -lkrb -lcrypt -lcom_err -lmp -lipsec
.include <bsd.prog.mk>

View File

@ -8,7 +8,7 @@ MAN8= telnetd.8
CFLAGS+= -DLINEMODE -DUSE_TERMIO -DDIAGNOSTICS -DOLD_ENVIRON \
-DENV_HACK -DAUTHENTICATION -DENCRYPTION \
-I${TELNETDIR}
-I${TELNETDIR} -DINET6
SRCS= global.c slc.c state.c sys_term.c telnetd.c \
termstat.c utility.c authenc.c

View File

@ -4,15 +4,15 @@ PROG= telnet
CFLAGS+= -DKLUDGELINEMODE -DUSE_TERMIO -DENV_HACK -DSKEY \
-DENCRYPTION -DAUTHENTICATION -DKRB4 \
-I${TELNETDIR}
-I${TELNETDIR} -DIPSEC -DINET6
SRCS= authenc.c commands.c main.c network.c ring.c sys_bsd.c \
telnet.c terminal.c tn3270.c utilities.c
DPADD= ${LIBTERMCAP} ${LIBTELNET} ${LIBDES} ${LIBKRB} ${LIBCRYPT} \
${LIBCOM_ERR}
${LIBCOM_ERR} ${LIBIPSEC}
LDADD= -ltermcap -L${TELNETOBJDIR} -ltelnet -ldes \
-L${KRBOBJDIR} -lkrb -lcrypt -lcom_err -lmp
-L${KRBOBJDIR} -lkrb -lcrypt -lcom_err -lmp -lipsec
.include <bsd.prog.mk>

View File

@ -7,6 +7,7 @@ SRCS= ftpd.c ftpcmd.y logwtmp.c popen.c skey-stuff.c
CFLAGS+=-DSETPROCTITLE -DSKEY -DLOGIN_CAP -DVIRTUAL_HOSTING -Wall \
-I${.CURDIR}/../../contrib-crypto/telnet
CFLAGS+=-DINET6 -g
YFLAGS=
LDADD= -lskey -lmd -lcrypt -lutil

View File

@ -49,6 +49,7 @@ void makedir __P((char *));
void nack __P((char *));
void pass __P((char *));
void passive __P((void));
void long_passive __P((char *, int));
void perror_reply __P((int, char *));
void pwd __P((void));
void removedir __P((char *));
@ -71,3 +72,18 @@ int yyparse __P((void));
char *skey_challenge __P((char *, struct passwd *, int));
#endif
int ls_main __P((int, char **));
struct sockaddr_in;
struct sockaddr_in6;
union sockunion {
struct sockinet {
u_char si_len;
u_char si_family;
u_short si_port;
} su_si;
struct sockaddr_in su_sin;
struct sockaddr_in6 su_sin6;
};
#define su_len su_si.si_len
#define su_family su_si.si_family
#define su_port su_si.si_port

View File

@ -58,6 +58,7 @@ static const char rcsid[] =
#include <ctype.h>
#include <errno.h>
#include <glob.h>
#include <netdb.h>
#include <pwd.h>
#include <setjmp.h>
#include <signal.h>
@ -71,7 +72,7 @@ static const char rcsid[] =
#include "extern.h"
extern struct sockaddr_in data_dest, his_addr;
extern union sockunion data_dest, his_addr;
extern int logged_in;
extern struct passwd *pw;
extern int guest;
@ -98,6 +99,8 @@ static int cmd_bytesz;
char cbuf[512];
char *fromname;
extern int epsvall;
%}
%union {
@ -108,6 +111,7 @@ char *fromname;
%token
A B C E F I
L N P R S T
ALL
SP CRLF COMMA
@ -118,6 +122,7 @@ char *fromname;
ABOR DELE CWD LIST NLST SITE
STAT HELP NOOP MKD RMD PWD
CDUP STOU SMNT SYST SIZE MDTM
LPRT LPSV EPRT EPSV
UMASK IDLE CHMOD
@ -128,7 +133,8 @@ char *fromname;
%type <i> check_login octal_number byte_size
%type <i> struct_code mode_code type_code form_code
%type <s> pathstring pathname password username
%type <s> pathstring pathname password username ext_arg
%type <s> ALL
%start cmd_list
@ -157,31 +163,194 @@ cmd
}
| PORT check_login SP host_port CRLF
{
if ($2) {
if (paranoid &&
((ntohs(data_dest.sin_port) <
IPPORT_RESERVED) ||
memcmp(&data_dest.sin_addr,
&his_addr.sin_addr,
sizeof(data_dest.sin_addr)))) {
usedefault = 1;
reply(500,
"Illegal PORT range rejected.");
} else {
usedefault = 0;
if (pdata >= 0) {
(void) close(pdata);
pdata = -1;
}
reply(200, "PORT command successful.");
}
if (epsvall) {
reply(501, "no PORT allowed after EPSV ALL");
goto port_done;
}
if (!$2)
goto port_done;
if (port_check("PORT") == 1)
goto port_done;
#ifdef INET6
if ((his_addr.su_family != AF_INET6 ||
!IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr))) {
/* shoud never happen */
usedefault = 1;
reply(500, "Invalid address rejected.");
goto port_done;
}
port_check_v6("pcmd");
#endif
port_done:
}
| LPRT check_login SP host_long_port CRLF
{
if (epsvall) {
reply(501, "no LPRT allowed after EPSV ALL");
goto lprt_done;
}
if (!$2)
goto lprt_done;
if (port_check("LPRT") == 1)
goto lprt_done;
#ifdef INET6
if (his_addr.su_family != AF_INET6) {
usedefault = 1;
reply(500, "Invalid address rejected.");
goto lprt_done;
}
if (port_check_v6("LPRT") == 1)
goto lprt_done;
#endif
lprt_done:
}
| EPRT check_login SP STRING CRLF
{
char delim;
char *tmp = NULL;
char *p, *q;
char *result[3];
struct addrinfo hints;
struct addrinfo *res;
int i;
if (epsvall) {
reply(501, "no EPRT allowed after EPSV ALL");
goto eprt_done;
}
if (!$2)
goto eprt_done;
memset(&data_dest, 0, sizeof(data_dest));
tmp = strdup($4);
if (debug)
syslog(LOG_DEBUG, "%s", tmp);
if (!tmp) {
fatal("not enough core");
/*NOTREACHED*/
}
p = tmp;
delim = p[0];
p++;
memset(result, 0, sizeof(result));
for (i = 0; i < 3; i++) {
q = strchr(p, delim);
if (!q || *q != delim) {
parsefail:
reply(500,
"Invalid argument, rejected.");
if (tmp)
free(tmp);
usedefault = 1;
goto eprt_done;
}
*q++ = '\0';
result[i] = p;
if (debug)
syslog(LOG_DEBUG, "%d: %s", i, p);
p = q;
}
/* some more sanity check */
p = result[0];
while (*p) {
if (!isdigit(*p))
goto parsefail;
p++;
}
p = result[2];
while (*p) {
if (!isdigit(*p))
goto parsefail;
p++;
}
/* grab address */
memset(&hints, 0, sizeof(hints));
if (atoi(result[0]) == 1)
hints.ai_family = PF_INET;
#ifdef INET6
else if (atoi(result[0]) == 2)
hints.ai_family = PF_INET6;
#endif
else
hints.ai_family = PF_UNSPEC; /*XXX*/
hints.ai_socktype = SOCK_STREAM;
i = getaddrinfo(result[1], result[2], &hints, &res);
if (i)
goto parsefail;
memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
#ifdef INET6
if (his_addr.su_family == AF_INET6
&& data_dest.su_family == AF_INET6) {
/* XXX more sanity checks! */
data_dest.su_sin6.sin6_scope_id =
his_addr.su_sin6.sin6_scope_id;
}
#endif
free(tmp);
tmp = NULL;
if (port_check("EPRT") == 1)
goto eprt_done;
#ifdef INET6
if (his_addr.su_family != AF_INET6) {
usedefault = 1;
reply(500, "Invalid address rejected.");
goto eprt_done;
}
if (port_check_v6("EPRT") == 1)
goto eprt_done;
#endif
eprt_done:;
}
| PASV check_login CRLF
{
if ($2)
if (epsvall)
reply(501, "no PASV allowed after EPSV ALL");
else if ($2)
passive();
}
| LPSV check_login CRLF
{
if (epsvall)
reply(501, "no LPSV allowed after EPSV ALL");
else if ($2)
long_passive("LPSV", PF_UNSPEC);
}
| EPSV check_login SP NUMBER CRLF
{
if ($2) {
int pf;
switch ($4) {
case 1:
pf = PF_INET;
break;
#ifdef INET6
case 2:
pf = PF_INET6;
break;
#endif
default:
pf = -1; /*junk value*/
break;
}
long_passive("EPSV", pf);
}
}
| EPSV check_login SP ALL CRLF
{
if ($2) {
reply(200,
"EPSV ALL command successful.");
epsvall++;
}
}
| EPSV check_login CRLF
{
if ($2)
long_passive("EPSV", PF_UNSPEC);
}
| TYPE SP type_code CRLF
{
switch (cmd_type) {
@ -576,15 +745,61 @@ host_port
{
char *a, *p;
data_dest.sin_len = sizeof(struct sockaddr_in);
data_dest.sin_family = AF_INET;
p = (char *)&data_dest.sin_port;
data_dest.su_len = sizeof(struct sockaddr_in);
data_dest.su_family = AF_INET;
p = (char *)&data_dest.su_sin.sin_port;
p[0] = $9; p[1] = $11;
a = (char *)&data_dest.sin_addr;
a = (char *)&data_dest.su_sin.sin_addr;
a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7;
}
;
host_long_port
: NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
NUMBER
{
char *a, *p;
memset(&data_dest, 0, sizeof(data_dest));
data_dest.su_len = sizeof(struct sockaddr_in6);
data_dest.su_family = AF_INET6;
p = (char *)&data_dest.su_port;
p[0] = $39; p[1] = $41;
a = (char *)&data_dest.su_sin6.sin6_addr;
a[0] = $5; a[1] = $7; a[2] = $9; a[3] = $11;
a[4] = $13; a[5] = $15; a[6] = $17; a[7] = $19;
a[8] = $21; a[9] = $23; a[10] = $25; a[11] = $27;
a[12] = $29; a[13] = $31; a[14] = $33; a[15] = $35;
if (his_addr.su_family == AF_INET6) {
/* XXX more sanity checks! */
data_dest.su_sin6.sin6_scope_id =
his_addr.su_sin6.sin6_scope_id;
}
if ($1 != 6 || $3 != 16 || $37 != 2)
memset(&data_dest, 0, sizeof(data_dest));
}
| NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
NUMBER
{
char *a, *p;
memset(&data_dest, 0, sizeof(data_dest));
data_dest.su_sin.sin_len = sizeof(struct sockaddr_in);
data_dest.su_family = AF_INET;
p = (char *)&data_dest.su_port;
p[0] = $15; p[1] = $17;
a = (char *)&data_dest.su_sin.sin_addr;
a[0] = $5; a[1] = $7; a[2] = $9; a[3] = $11;
if ($1 != 4 || $3 != 4 || $13 != 2)
memset(&data_dest, 0, sizeof(data_dest));
}
;
form_code
: N
{
@ -774,7 +989,11 @@ struct tab cmdtab[] = { /* In order defined in RFC 765 */
{ "REIN", REIN, ARGS, 0, "(reinitialize server state)" },
{ "QUIT", QUIT, ARGS, 1, "(terminate service)", },
{ "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4" },
{ "LPRT", LPRT, ARGS, 1, "<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." },
{ "EPRT", EPRT, STR1, 1, "<sp> |af|addr|port|" },
{ "PASV", PASV, ARGS, 1, "(set server in passive mode)" },
{ "LPSV", LPSV, ARGS, 1, "(set server in passive mode)" },
{ "EPSV", EPSV, ARGS, 1, "[<sp> af|ALL]" },
{ "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]" },
{ "STRU", STRU, ARGS, 1, "(specify file structure)" },
{ "MODE", MODE, ARGS, 1, "(specify transfer mode)" },
@ -829,8 +1048,11 @@ static char *copy __P((char *));
static void help __P((struct tab *, char *));
static struct tab *
lookup __P((struct tab *, char *));
static int port_check __P((const char *));
static int port_check_v6 __P((const char *));
static void sizecmd __P((char *));
static void toolong __P((int));
static void v4map_data_dest __P((void));
static int yylex __P((void));
static struct tab *
@ -1085,6 +1307,11 @@ yylex()
cbuf[cpos] = c;
return (NUMBER);
}
if (strncasecmp(&cbuf[cpos], "ALL", 3) == 0
&& !isalnum(cbuf[cpos + 3])) {
cpos += 3;
return ALL;
}
switch (cbuf[cpos++]) {
case '\n':
@ -1289,3 +1516,94 @@ sizecmd(filename)
reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]);
}
}
/* Return 1, if port check is done. Return 0, if not yet. */
static int
port_check(pcmd)
const char *pcmd;
{
if (his_addr.su_family == AF_INET) {
if (data_dest.su_family != AF_INET) {
usedefault = 1;
reply(500, "Invalid address rejected.");
return 1;
}
if (paranoid &&
((ntohs(data_dest.su_port) < IPPORT_RESERVED) ||
memcmp(&data_dest.su_sin.sin_addr,
&his_addr.su_sin.sin_addr,
sizeof(data_dest.su_sin.sin_addr)))) {
usedefault = 1;
reply(500, "Illegal PORT range rejected.");
} else {
usedefault = 0;
if (pdata >= 0) {
(void) close(pdata);
pdata = -1;
}
reply(200, "%s command successful.", pcmd);
}
return 1;
}
return 0;
}
#ifdef INET6
/* Return 1, if port check is done. Return 0, if not yet. */
static int
port_check_v6(pcmd)
const char *pcmd;
{
if (his_addr.su_family == AF_INET6) {
if (IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr))
/* Convert data_dest into v4 mapped sockaddr.*/
v4map_data_dest();
if (data_dest.su_family != AF_INET6) {
usedefault = 1;
reply(500, "Invalid address rejected.");
return 1;
}
if (paranoid &&
((ntohs(data_dest.su_port) < IPPORT_RESERVED) ||
memcmp(&data_dest.su_sin6.sin6_addr,
&his_addr.su_sin6.sin6_addr,
sizeof(data_dest.su_sin6.sin6_addr)))) {
usedefault = 1;
reply(500, "Illegal PORT range rejected.");
} else {
usedefault = 0;
if (pdata >= 0) {
(void) close(pdata);
pdata = -1;
}
reply(200, "%s command successful.", pcmd);
}
return 1;
}
return 0;
}
static void
v4map_data_dest()
{
struct in_addr savedaddr;
int savedport;
if (data_dest.su_family != AF_INET) {
usedefault = 1;
reply(500, "Invalid address rejected.");
return;
}
savedaddr = data_dest.su_sin.sin_addr;
savedport = data_dest.su_port;
memset(&data_dest, 0, sizeof(data_dest));
data_dest.su_sin6.sin6_len = sizeof(struct sockaddr_in6);
data_dest.su_sin6.sin6_family = AF_INET6;
data_dest.su_sin6.sin6_port = savedport;
memset((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[10], 0xff, 2);
memcpy((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[12],
(caddr_t)&savedaddr, sizeof(savedaddr));
}
#endif

View File

@ -32,7 +32,7 @@
.\" @(#)ftpd.8 8.2 (Berkeley) 4/19/94
.\" $FreeBSD$
.\"
.Dd April 19, 1994
.Dd January 27, 2000
.Dt FTPD 8
.Os BSD 4.2
.Sh NAME
@ -41,6 +41,8 @@
Internet File Transfer Protocol server
.Sh SYNOPSIS
.Nm ftpd
.Op Fl 4
.Op Fl 6
.Op Fl d
.Op Fl l Op Fl l
.Op Fl A
@ -135,6 +137,20 @@ When
.Fl D
is specified, write the daemon's process ID to
.Ar file .
.It Fl 6
When
.Fl D
is specified, accept connections via AF_INET6 socket.
.It Fl 4
When
.Fl D
is specified, accept IPv4 connections.
When
.Fl 6
is also specified, accept IPv4 connection via AF_INET6 socket.
When
.Fl 6
is not specified, accept IPv4 connection via AF_INET socket.
.It Fl A
Allow only anonymous ftp access.
.El
@ -203,6 +219,10 @@ The case of the requests is ignored.
.It XMKD Ta "make a directory (deprecated)"
.It XPWD Ta "print the current working directory (deprecated)"
.It XRMD Ta "remove a directory (deprecated)"
.It LPSV Ta "prepare for server-to-server transfer, multiprotocol"
.It LPRT Ta "specify data connection port, multiprotocol"
.It EPSV Ta "prepare for server-to-server transfer, multiprotocol"
.It EPRT Ta "specify data connection port, multiprotocol"
.El
.Pp
The following non-standard or
@ -453,3 +473,4 @@ The
.Nm
command appeared in
.Bx 4.2 .
IPv6 support was added in WIDE Hydrangea IPv6 stack kit.

View File

@ -110,15 +110,20 @@ static const char rcsid[] =
static char version[] = "Version 6.00LS";
#undef main
/* wrapper for KAME-special getnameinfo() */
#ifndef NI_WITHSCOPEID
#define NI_WITHSCOPEID 0
#endif
extern off_t restart_point;
extern char cbuf[];
struct sockaddr_in server_addr;
struct sockaddr_in ctrl_addr;
struct sockaddr_in data_source;
struct sockaddr_in data_dest;
struct sockaddr_in his_addr;
struct sockaddr_in pasv_addr;
union sockunion server_addr;
union sockunion ctrl_addr;
union sockunion data_source;
union sockunion data_dest;
union sockunion his_addr;
union sockunion pasv_addr;
int daemon_mode;
int data;
@ -155,9 +160,11 @@ char *hostname;
#ifdef VIRTUAL_HOSTING
char *ftpuser;
int epsvall = 0;
static struct ftphost {
struct ftphost *next;
struct in_addr hostaddr;
union sockunion hostaddr;
char *hostname;
char *anonuser;
char *statfile;
@ -176,7 +183,6 @@ char *tty = ttyline; /* for klogin */
static int auth_pam __P((struct passwd**, const char*));
#endif
struct in_addr bind_address;
char *pid_file = NULL;
/*
@ -200,7 +206,7 @@ char proctitle[LINE_MAX]; /* initial part of title */
#ifdef SKEY
int pwok = 0;
char addr_string[20]; /* XXX */
char addr_string[INET6_ADDRSTRLEN]; /* XXX */
#endif
#define LOGCMD(cmd, file) \
@ -224,13 +230,13 @@ char addr_string[20]; /* XXX */
#ifdef VIRTUAL_HOSTING
static void inithosts __P((void));
static void selecthost __P((struct in_addr *));
static void selecthost __P((union sockunion *));
#endif
static void ack __P((char *));
static void myoob __P((int));
static int checkuser __P((char *, char *, int));
static FILE *dataconn __P((char *, off_t, char *));
static void dolog __P((struct sockaddr_in *));
static void dolog __P((struct sockaddr *));
static char *curdir __P((void));
static void end_login __P((void));
static FILE *getdatasock __P((char *));
@ -266,6 +272,10 @@ main(argc, argv, envp)
int addrlen, ch, on = 1, tos;
char *cp, line[LINE_MAX];
FILE *fd;
int error;
char *bindname = NULL;
int family = AF_UNSPEC;
int enable_v4 = 0;
tzset(); /* in case no timezone database in ~ftp */
@ -280,8 +290,7 @@ main(argc, argv, envp)
#endif /* OLD_SETPROCTITLE */
bind_address.s_addr = htonl(INADDR_ANY);
while ((ch = getopt(argc, argv, "AdlDSURt:T:u:va:p:")) != -1) {
while ((ch = getopt(argc, argv, "AdlDSURt:T:u:va:p:46")) != -1) {
switch (ch) {
case 'D':
daemon_mode++;
@ -320,8 +329,7 @@ main(argc, argv, envp)
break;
case 'a':
if (!inet_aton(optarg, &bind_address))
errx(1, "invalid address for -a");
bindname = optarg;
break;
case 'p':
@ -347,6 +355,16 @@ main(argc, argv, envp)
debug = 1;
break;
case '4':
enable_v4 = 1;
if (family == AF_UNSPEC)
family = AF_INET;
break;
case '6':
family = AF_INET6;
break;
default:
warnx("unknown flag -%c ignored", optopt);
break;
@ -366,7 +384,7 @@ main(argc, argv, envp)
if (daemon_mode) {
int ctl_sock, fd;
struct servent *sv;
struct addrinfo hints, *res;
/*
* Detach from parent.
@ -376,30 +394,56 @@ main(argc, argv, envp)
exit(1);
}
(void) signal(SIGCHLD, reapchild);
/*
* Get port number for ftp/tcp.
*/
sv = getservbyname("ftp", "tcp");
if (sv == NULL) {
syslog(LOG_ERR, "getservbyname for ftp failed");
/* init bind_sa */
memset(&hints, 0, sizeof(hints));
hints.ai_family = family == AF_UNSPEC ? AF_INET : family;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
hints.ai_flags = AI_PASSIVE;
error = getaddrinfo(bindname, "ftp", &hints, &res);
if (error) {
if (family == AF_UNSPEC) {
hints.ai_family = AF_UNSPEC;
error = getaddrinfo(bindname, "ftp", &hints,
&res);
}
if (error == 0 && res->ai_addr != NULL)
family = res->ai_addr->sa_family;
}
if (error) {
syslog(LOG_ERR, gai_strerror(error));
if (error == EAI_SYSTEM)
syslog(LOG_ERR, strerror(errno));
exit(1);
}
if (res->ai_addr == NULL) {
syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname);
exit(1);
}
/*
* Open a socket, bind it to the FTP port, and start
* listening.
*/
ctl_sock = socket(AF_INET, SOCK_STREAM, 0);
ctl_sock = socket(family, SOCK_STREAM, 0);
if (ctl_sock < 0) {
syslog(LOG_ERR, "control socket: %m");
exit(1);
}
if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on)) < 0)
syslog(LOG_ERR, "control setsockopt: %m");;
server_addr.sin_family = AF_INET;
server_addr.sin_addr = bind_address;
server_addr.sin_port = sv->s_port;
if (bind(ctl_sock, (struct sockaddr *)&server_addr, sizeof(server_addr))) {
syslog(LOG_ERR, "control setsockopt: %m");
#ifdef IPV6_BINDV6ONLY
if (family == AF_INET6 && enable_v4 == 0) {
if (setsockopt(ctl_sock, IPPROTO_IPV6, IPV6_BINDV6ONLY,
(char *)&on, sizeof (on)) < 0)
syslog(LOG_ERR,
"control setsockopt(IPV6_BINDV6ONLY): %m");
}
#endif /* IPV6_BINDV6ONLY */
memcpy(&server_addr, res->ai_addr, res->ai_addr->sa_len);
if (bind(ctl_sock, (struct sockaddr *)&server_addr,
server_addr.su_len) < 0) {
syslog(LOG_ERR, "control bind: %m");
exit(1);
}
@ -434,7 +478,7 @@ main(argc, argv, envp)
* children to handle them.
*/
while (1) {
addrlen = sizeof(his_addr);
addrlen = server_addr.su_len;
fd = accept(ctl_sock, (struct sockaddr *)&his_addr, &addrlen);
if (fork() == 0) {
/* child */
@ -459,7 +503,9 @@ main(argc, argv, envp)
syslog(LOG_ERR, "signal: %m");
#ifdef SKEY
strncpy(addr_string, inet_ntoa(his_addr.sin_addr), sizeof(addr_string));
getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
addr_string, sizeof(addr_string) - 1, NULL, 0,
NI_NUMERICHOST|NI_WITHSCOPEID);
#endif
addrlen = sizeof(ctrl_addr);
if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
@ -468,12 +514,15 @@ main(argc, argv, envp)
}
#ifdef VIRTUAL_HOSTING
/* select our identity from virtual host table */
selecthost(&ctrl_addr.sin_addr);
selecthost(&ctrl_addr);
#endif
#ifdef IP_TOS
if (ctrl_addr.su_family == AF_INET)
{
tos = IPTOS_LOWDELAY;
if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
}
#endif
/*
* Disable Nagle on the control channel so that we don't have to wait
@ -482,7 +531,7 @@ main(argc, argv, envp)
if (setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
syslog(LOG_WARNING, "control setsockopt TCP_NODELAY: %m");
data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
data_source.su_port = htons(ntohs(ctrl_addr.su_port) - 1);
/* set this here so klogin can use it... */
(void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());
@ -497,7 +546,7 @@ main(argc, argv, envp)
if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
syslog(LOG_ERR, "fcntl F_SETOWN: %m");
#endif
dolog(&his_addr);
dolog((struct sockaddr *)&his_addr);
/*
* Set up default state
*/
@ -567,9 +616,9 @@ inithosts()
{
FILE *fp;
char *cp;
struct hostent *hp;
struct ftphost *hrp, *lhrp;
char line[1024];
struct addrinfo hints, *res, *ai;
/*
* Fill in the default host information
@ -579,20 +628,28 @@ inithosts()
if ((hrp = malloc(sizeof(struct ftphost))) == NULL ||
(hrp->hostname = strdup(line)) == NULL)
fatal("Ran out of memory.");
memset(&hrp->hostaddr, 0, sizeof hrp->hostaddr);
if ((hp = gethostbyname(hrp->hostname)) != NULL)
(void) memcpy(&hrp->hostaddr,
hp->h_addr_list[0],
sizeof(hrp->hostaddr));
memset(&hrp->hostaddr, 0, sizeof(hrp->hostaddr));
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_UNSPEC;
getaddrinfo(hrp->hostname, NULL, &hints, &res);
if (res)
memcpy(&hrp->hostaddr, res->ai_addr, res->ai_addrlen);
hrp->statfile = _PATH_FTPDSTATFILE;
hrp->welcome = _PATH_FTPWELCOME;
hrp->loginmsg = _PATH_FTPLOGINMESG;
hrp->anonuser = "ftp";
hrp->next = NULL;
thishost = firsthost = lhrp = hrp;
freeaddrinfo(res);
if ((fp = fopen(_PATH_FTPHOSTS, "r")) != NULL) {
int addrsize, error;
void *addr;
struct hostent *hp;
while (fgets(line, sizeof(line), fp) != NULL) {
int i;
int i, hp_error;
if ((cp = strchr(line, '\n')) == NULL) {
/* ignore long lines */
@ -606,13 +663,21 @@ inithosts()
/* skip comments and empty lines */
if (cp == NULL || line[0] == '#')
continue;
/* first, try a standard gethostbyname() */
if ((hp = gethostbyname(cp)) == NULL)
hints.ai_flags = 0;
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_PASSIVE;
error = getaddrinfo(cp, NULL, &hints, &res);
if (error != NULL)
continue;
for (ai = res; ai != NULL && ai->ai_addr != NULL;
ai = ai->ai_next)
{
for (hrp = firsthost; hrp != NULL; hrp = hrp->next) {
if (memcmp(&hrp->hostaddr,
hp->h_addr_list[0],
sizeof(hrp->hostaddr)) == 0)
ai->ai_addr,
ai->ai_addr->sa_len) == 0)
break;
}
if (hrp == NULL) {
@ -628,16 +693,32 @@ inithosts()
lhrp = hrp;
}
(void) memcpy(&hrp->hostaddr,
hp->h_addr_list[0],
sizeof(hrp->hostaddr));
ai->ai_addr,
ai->ai_addr->sa_len);
/*
* determine hostname to use.
* force defined name if it is a valid alias
* force defined name if there is a valid alias
* otherwise fallback to primary hostname
*/
if ((hp = gethostbyaddr((char*)&hrp->hostaddr,
sizeof(hrp->hostaddr),
AF_INET)) != NULL) {
/* XXX: getaddrinfo() can't do alias check */
switch(hrp->hostaddr.su_family) {
case AF_INET:
addr = &((struct sockaddr_in *)&hrp->hostaddr)->sin_addr;
addrsize = sizeof(struct sockaddr_in);
break;
case AF_INET6:
addr = &((struct sockaddr_in6 *)&hrp->hostaddr)->sin6_addr;
addrsize = sizeof(struct sockaddr_in6);
break;
default:
/* should not reach here */
free(hrp);
continue;
/* NOTREACHED */
}
if ((hp = getipnodebyaddr((char*)addr, addrsize,
hrp->hostaddr.su_family,
&hp_error)) != NULL) {
if (strcmp(cp, hp->h_name) != 0) {
if (hp->h_aliases == NULL)
cp = hp->h_name;
@ -652,6 +733,7 @@ inithosts()
}
}
hrp->hostname = strdup(cp);
freehostent(hp);
/* ok, now we now peel off the rest */
i = 0;
while (i < 4 && (cp = strtok(NULL, " \t")) != NULL) {
@ -673,25 +755,55 @@ inithosts()
}
++i;
}
/* XXX: re-initialization for getaddrinfo() loop */
cp = strtok(line, " \t");
}
}
(void) fclose(fp);
}
}
static void
selecthost(a)
struct in_addr *a;
selecthost(su)
union sockunion *su;
{
struct ftphost *hrp;
u_int16_t port;
#ifdef INET6
struct in6_addr *mapped_in6 = NULL;
#endif
#ifdef INET6
/*
* XXX IPv4 mapped IPv6 addr consideraton,
* specified in rfc2373.
*/
if (su->su_family == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&su->su_sin6.sin6_addr))
mapped_in6 = &su->su_sin6.sin6_addr;
#endif
hrp = thishost = firsthost; /* default */
port = su->su_port;
su->su_port = 0;
while (hrp != NULL) {
if (memcmp(a, &hrp->hostaddr, sizeof(hrp->hostaddr)) == 0) {
if (memcmp(su, &hrp->hostaddr, sizeof(hrp->hostaddr)) == 0) {
thishost = hrp;
break;
}
#ifdef INET6
/* XXX IPv4 mapped IPv6 addr consideraton */
if (hrp->hostaddr.su_family == AF_INET && mapped_in6 != NULL &&
(memcmp(&mapped_in6->s6_addr[12],
&hrp->hostaddr.su_sin.sin_addr,
sizeof(struct in_addr)) == 0)) {
thishost = hrp;
break;
}
#endif
hrp = hrp->next;
}
su->su_port = port;
/* setup static variables as appropriate */
hostname = thishost->hostname;
ftpuser = thishost->anonuser;
@ -1107,8 +1219,9 @@ pass(passwd)
if ((lc = login_getpwclass(pw)) != NULL) {
char remote_ip[MAXHOSTNAMELEN];
strncpy(remote_ip, inet_ntoa(his_addr.sin_addr),
sizeof(remote_ip) - 1);
getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
remote_ip, sizeof(remote_ip) - 1, NULL, 0,
NI_NUMERICHOST|NI_WITHSCOPEID);
remote_ip[sizeof(remote_ip) - 1] = 0;
if (!auth_hostok(lc, remotehost, remote_ip)) {
syslog(LOG_INFO|LOG_AUTH,
@ -1402,19 +1515,19 @@ getdatasock(mode)
if (data >= 0)
return (fdopen(data, mode));
(void) seteuid((uid_t)0);
s = socket(AF_INET, SOCK_STREAM, 0);
s = socket(data_dest.su_family, SOCK_STREAM, 0);
if (s < 0)
goto bad;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
(char *) &on, sizeof(on)) < 0)
goto bad;
/* anchor socket to avoid multi-homing problems */
data_source.sin_len = sizeof(struct sockaddr_in);
data_source.sin_family = AF_INET;
data_source.sin_addr = ctrl_addr.sin_addr;
data_source = ctrl_addr;
data_source.su_port = htons(20); /* ftp-data port */
for (tries = 1; ; tries++) {
if (bind(s, (struct sockaddr *)&data_source,
sizeof(data_source)) >= 0)
data_source.su_len) >= 0)
break;
if (errno != EADDRINUSE || tries > 10)
goto bad;
@ -1422,9 +1535,12 @@ getdatasock(mode)
}
(void) seteuid((uid_t)pw->pw_uid);
#ifdef IP_TOS
if (data_source.su_family == AF_INET)
{
on = IPTOS_THROUGHPUT;
if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
}
#endif
#ifdef TCP_NOPUSH
/*
@ -1470,8 +1586,8 @@ dataconn(name, size, mode)
else
*sizebuf = '\0';
if (pdata >= 0) {
struct sockaddr_in from;
int s, fromlen = sizeof(from);
union sockunion from;
int s, fromlen = ctrl_addr.su_len;
struct timeval timeout;
fd_set set;
@ -1491,9 +1607,12 @@ dataconn(name, size, mode)
(void) close(pdata);
pdata = s;
#ifdef IP_TOS
if (from.su_family == AF_INET)
{
tos = IPTOS_THROUGHPUT;
(void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
sizeof(int));
}
#endif
reply(150, "Opening %s mode data connection for '%s'%s.",
type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
@ -1510,14 +1629,18 @@ dataconn(name, size, mode)
usedefault = 1;
file = getdatasock(mode);
if (file == NULL) {
reply(425, "Can't create data socket (%s,%d): %s.",
inet_ntoa(data_source.sin_addr),
ntohs(data_source.sin_port), strerror(errno));
char hostbuf[BUFSIZ], portbuf[BUFSIZ];
getnameinfo((struct sockaddr *)&data_source,
data_source.su_len, hostbuf, sizeof(hostbuf) - 1,
portbuf, sizeof(portbuf),
NI_NUMERICHOST|NI_NUMERICSERV|NI_WITHSCOPEID);
reply(425, "Can't create data socket (%s,%s): %s.",
hostbuf, portbuf, strerror(errno));
return (NULL);
}
data = fileno(file);
while (connect(data, (struct sockaddr *)&data_dest,
sizeof(data_dest)) < 0) {
data_dest.su_len) < 0) {
if (errno == EADDRINUSE && retry < swaitmax) {
sleep((unsigned) swaitint);
retry += swaitint;
@ -1768,14 +1891,20 @@ statfilecmd(filename)
void
statcmd()
{
struct sockaddr_in *sin;
union sockunion *su;
u_char *a, *p;
char hname[INET6_ADDRSTRLEN];
int ispassive;
lreply(211, "%s FTP server status:", hostname, version);
printf(" %s\r\n", version);
printf(" Connected to %s", remotehost);
if (!isdigit(remotehost[0]))
printf(" (%s)", inet_ntoa(his_addr.sin_addr));
if (!getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
hname, sizeof(hname) - 1, NULL, 0,
NI_NUMERICHOST|NI_WITHSCOPEID)) {
if (strcmp(hname, remotehost) != 0)
printf(" (%s)", hname);
}
printf("\r\n");
if (logged_in) {
if (guest)
@ -1800,18 +1929,85 @@ statcmd()
if (data != -1)
printf(" Data connection open\r\n");
else if (pdata != -1) {
printf(" in Passive mode");
sin = &pasv_addr;
ispassive = 1;
su = &pasv_addr;
goto printaddr;
} else if (usedefault == 0) {
printf(" PORT");
sin = &data_dest;
ispassive = 0;
su = &data_dest;
printaddr:
a = (u_char *) &sin->sin_addr;
p = (u_char *) &sin->sin_port;
#define UC(b) (((int) b) & 0xff)
printf(" (%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 (epsvall) {
printf(" EPSV only mode (EPSV ALL)\r\n");
goto epsvonly;
}
/* PORT/PASV */
if (su->su_family == AF_INET) {
a = (u_char *) &su->su_sin.sin_addr;
p = (u_char *) &su->su_sin.sin_port;
printf(" %s (%d,%d,%d,%d,%d,%d)\r\n",
ispassive ? "PASV" : "PORT",
UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
UC(p[0]), UC(p[1]));
}
/* LPRT/LPSV */
{
int alen, af, i;
switch (su->su_family) {
case AF_INET:
a = (u_char *) &su->su_sin.sin_addr;
p = (u_char *) &su->su_sin.sin_port;
alen = sizeof(su->su_sin.sin_addr);
af = 4;
break;
case AF_INET6:
a = (u_char *) &su->su_sin6.sin6_addr;
p = (u_char *) &su->su_sin6.sin6_port;
alen = sizeof(su->su_sin6.sin6_addr);
af = 6;
break;
default:
af = 0;
break;
}
if (af) {
printf(" %s (%d,%d,", ispassive ? "LPSV" : "LPRT",
af, alen);
for (i = 0; i < alen; i++)
printf("%d,", UC(a[i]));
printf("%d,%d,%d)\r\n", 2, UC(p[0]), UC(p[1]));
}
}
epsvonly:;
/* EPRT/EPSV */
{
int af;
switch (su->su_family) {
case AF_INET:
af = 1;
break;
case AF_INET6:
af = 2;
break;
default:
af = 0;
break;
}
if (af) {
if (!getnameinfo((struct sockaddr *)su, su->su_len,
hname, sizeof(hname) - 1, NULL, 0,
NI_NUMERICHOST)) {
printf(" %s |%d|%s|%d|\r\n",
ispassive ? "EPSV" : "EPRT",
af, hname, htons(su->su_port));
}
}
}
#undef UC
} else
printf(" No data connection\r\n");
@ -2015,10 +2211,12 @@ renamecmd(from, to)
}
static void
dolog(sin)
struct sockaddr_in *sin;
dolog(who)
struct sockaddr *who;
{
realhostname(remotehost, sizeof(remotehost) - 1, &sin->sin_addr);
int error;
realhostname_sa(remotehost, sizeof(remotehost) - 1, who, who->sa_len);
#ifdef SETPROCTITLE
#ifdef VIRTUAL_HOSTING
@ -2039,8 +2237,16 @@ dolog(sin)
remotehost, hostname);
else
#endif
{
char who_name[MAXHOSTNAMELEN];
error = getnameinfo(who, who->sa_len,
who_name, sizeof(who_name) - 1,
NULL, 0,
NI_NUMERICHOST|NI_WITHSCOPEID);
syslog(LOG_INFO, "connection from %s (%s)", remotehost,
inet_ntoa(sin->sin_addr));
error == 0 ? who_name : "");
}
}
}
@ -2112,7 +2318,7 @@ passive()
if (pdata >= 0) /* close old port if one set */
close(pdata);
pdata = socket(AF_INET, SOCK_STREAM, 0);
pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
if (pdata < 0) {
perror_reply(425, "Can't open passive connection");
return;
@ -2121,7 +2327,7 @@ passive()
(void) seteuid((uid_t)0);
#ifdef IP_PORTRANGE
{
if (ctrl_addr.su_family == AF_INET) {
int on = restricted_data_ports ? IP_PORTRANGE_HIGH
: IP_PORTRANGE_DEFAULT;
@ -2132,9 +2338,8 @@ passive()
#endif
pasv_addr = ctrl_addr;
pasv_addr.sin_port = 0;
if (bind(pdata, (struct sockaddr *)&pasv_addr,
sizeof(pasv_addr)) < 0)
pasv_addr.su_port = 0;
if (bind(pdata, (struct sockaddr *)&pasv_addr, pasv_addr.su_len) < 0)
goto pasv_error;
(void) seteuid((uid_t)pw->pw_uid);
@ -2144,8 +2349,15 @@ passive()
goto pasv_error;
if (listen(pdata, 1) < 0)
goto pasv_error;
a = (char *) &pasv_addr.sin_addr;
p = (char *) &pasv_addr.sin_port;
if (pasv_addr.su_family == AF_INET)
a = (char *) &pasv_addr.su_sin.sin_addr;
else if (pasv_addr.su_family == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&pasv_addr.su_sin6.sin6_addr))
a = (char *) &pasv_addr.su_sin6.sin6_addr.s6_addr[12];
else
goto pasv_error;
p = (char *) &pasv_addr.su_port;
#define UC(b) (((int) b) & 0xff)
@ -2161,6 +2373,121 @@ passive()
return;
}
/*
* Long Passive defined in RFC 1639.
* 228 Entering Long Passive Mode
* (af, hal, h1, h2, h3,..., pal, p1, p2...)
*/
void
long_passive(cmd, pf)
char *cmd;
int pf;
{
int len;
char *p, *a;
if (pdata >= 0) /* close old port if one set */
close(pdata);
if (pf != PF_UNSPEC) {
if (ctrl_addr.su_family != pf) {
switch (ctrl_addr.su_family) {
case AF_INET:
pf = 1;
break;
case AF_INET6:
pf = 2;
break;
default:
pf = 0;
break;
}
/*
* XXX
* only EPRT/EPSV ready clients will understand this
*/
if (strcmp(cmd, "EPSV") == 0 && pf) {
reply(522, "Network protocol mismatch, "
"use (%d)", pf);
} else
reply(501, "Network protocol mismatch"); /*XXX*/
return;
}
}
pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
if (pdata < 0) {
perror_reply(425, "Can't open passive connection");
return;
}
(void) seteuid((uid_t)0);
pasv_addr = ctrl_addr;
pasv_addr.su_port = 0;
len = pasv_addr.su_len;
if (bind(pdata, (struct sockaddr *)&pasv_addr, len) < 0)
goto pasv_error;
(void) seteuid((uid_t)pw->pw_uid);
if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
goto pasv_error;
if (listen(pdata, 1) < 0)
goto pasv_error;
#define UC(b) (((int) b) & 0xff)
if (strcmp(cmd, "LPSV") == 0) {
p = (char *)&pasv_addr.su_port;
switch (pasv_addr.su_family) {
case AF_INET:
a = (char *) &pasv_addr.su_sin.sin_addr;
v4_reply:
reply(228,
"Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d)",
4, 4, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
2, UC(p[0]), UC(p[1]));
return;
case AF_INET6:
if (IN6_IS_ADDR_V4MAPPED(&pasv_addr.su_sin6.sin6_addr)) {
a = (char *) &pasv_addr.su_sin6.sin6_addr.s6_addr[12];
goto v4_reply;
}
a = (char *) &pasv_addr.su_sin6.sin6_addr;
reply(228,
"Entering Long Passive Mode "
"(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",
6, 16, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
2, UC(p[0]), UC(p[1]));
return;
}
} else if (strcmp(cmd, "EPSV") == 0) {
switch (pasv_addr.su_family) {
case AF_INET:
case AF_INET6:
reply(229, "Entering Extended Passive Mode (|||%d|)",
ntohs(pasv_addr.su_port));
return;
}
} else {
/* more proper error code? */
}
pasv_error:
(void) seteuid((uid_t)pw->pw_uid);
(void) close(pdata);
pdata = -1;
perror_reply(425, "Can't open passive connection");
return;
}
/*
* Generate unique name for file with basename "local".
* The file named "local" is already known to exist.

View File

@ -43,6 +43,7 @@ static const char rcsid[] =
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <time.h>
@ -68,15 +69,23 @@ ftpd_logwtmp(line, name, host)
struct stat buf;
if (strlen(host) > UT_HOSTSIZE) {
struct hostent *hp = gethostbyname(host);
struct addrinfo hints, *res;
int error;
static char hostbuf[BUFSIZ];
if (hp != NULL) {
struct in_addr in;
memmove(&in, hp->h_addr, sizeof(in));
host = inet_ntoa(in);
} else
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
error = getaddrinfo(host, NULL, &hints, &res);
if (error)
host = "invalid hostname";
else {
getnameinfo(res->ai_addr, res->ai_addrlen,
hostbuf, sizeof(hostbuf), NULL, 0,
NI_NUMERICHOST);
host = hostbuf;
if (strlen(host) > UT_HOSTSIZE)
host[UT_HOSTSIZE] = '\0';
}
}
if (fd < 0 && (fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0)

View File

@ -44,6 +44,7 @@ static const char rcsid[] =
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <errno.h>
#include <glob.h>

View File

@ -8,7 +8,7 @@ MAN8= telnetd.8
CFLAGS+= -DLINEMODE -DUSE_TERMIO -DDIAGNOSTICS -DOLD_ENVIRON \
-DENV_HACK -DAUTHENTICATION -DENCRYPTION \
-I${TELNETDIR}
-I${TELNETDIR} -DINET6
SRCS= global.c slc.c state.c sys_term.c telnetd.c \
termstat.c utility.c authenc.c

View File

@ -4,12 +4,15 @@ PROG= telnet
CFLAGS+= -DKLUDGELINEMODE -DUSE_TERMIO -DENV_HACK -DSKEY \
-DENCRYPTION -DAUTHENTICATION -I${TELNETDIR}
CFLAGS+= -DIPSEC -DINET6
SRCS= authenc.c commands.c main.c network.c ring.c sys_bsd.c \
telnet.c terminal.c tn3270.c utilities.c
DPADD= ${LIBTERMCAP} ${LIBTELNET} ${LIBDES} ${LIBCRYPT} ${LIBMP}
DPADD+= ${LIBIPSEC}
LDADD= -ltermcap -L${TELNETOBJDIR} -ltelnet -ldes -lcrypt -lmp
LDADD+= -lipsec
.include <bsd.prog.mk>

View File

@ -10,6 +10,7 @@ PROG= ftp
SRCS= cmds.c cmdtab.c complete.c domacro.c fetch.c ftp.c main.c ruserpass.c \
util.c
CFLAGS+=-DINET6 -g
LDADD+= -ledit -ltermcap
DPADD+= ${LIBEDIT} ${LIBTERMCAP}

View File

@ -73,7 +73,7 @@ int getreply __P((int));
int globulize __P((char **));
char *gunique __P((const char *));
void help __P((int, char **));
char *hookup __P((const char *, int));
char *hookup __P((const char *, char *));
void idle __P((int, char **));
int initconn __P((void));
void intr __P((void));

View File

@ -57,6 +57,7 @@ __RCSID_SOURCE("$NetBSD: fetch.c,v 1.16.2.1 1997/11/18 01:00:22 mellon Exp $");
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <fcntl.h>
#include <signal.h>
@ -67,6 +68,11 @@ __RCSID_SOURCE("$NetBSD: fetch.c,v 1.16.2.1 1997/11/18 01:00:22 mellon Exp $");
#include "ftp_var.h"
/* wrapper for KAME-special getnameinfo() */
#ifndef NI_WITHSCOPEID
#define NI_WITHSCOPEID 0
#endif
static int url_get __P((const char *, const char *));
void aborthttp __P((int));
@ -91,9 +97,11 @@ url_get(origline, proxyenv)
const char *origline;
const char *proxyenv;
{
struct sockaddr_in sin;
struct addrinfo hints;
struct addrinfo *res;
char nameinfo[2 * INET6_ADDRSTRLEN + 1];
int i, out, isftpurl;
u_int16_t port;
char *port;
volatile int s;
size_t len;
char c, *cp, *ep, *portnum, *path, buf[4096];
@ -101,6 +109,7 @@ url_get(origline, proxyenv)
char *line, *proxy, *host;
volatile sig_t oldintr;
off_t hashbytes;
int error;
s = -1;
proxy = NULL;
@ -172,68 +181,69 @@ url_get(origline, proxyenv)
path = line;
}
portnum = strchr(host, ':'); /* find portnum */
if (portnum != NULL)
if (*host == '[' && (portnum = strrchr(host, ']'))) { /* IPv6 URL */
*portnum++ = '\0';
host++;
if (*portnum == ':')
portnum++;
else
portnum = NULL;
} else {
portnum = strrchr(host, ':'); /* find portnum */
if (portnum != NULL)
*portnum++ = '\0';
}
if (debug)
printf("host %s, port %s, path %s, save as %s.\n",
host, portnum, path, savefile);
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
if (isdigit((unsigned char)host[0])) {
if (inet_aton(host, &sin.sin_addr) == 0) {
warnx("Invalid IP address: %s", host);
goto cleanup_url_get;
}
} else {
struct hostent *hp;
hp = gethostbyname(host);
if (hp == NULL) {
warnx("%s: %s", host, hstrerror(h_errno));
goto cleanup_url_get;
}
if (hp->h_addrtype != AF_INET) {
warnx("%s: not an Internet address?", host);
goto cleanup_url_get;
}
memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
}
if (! EMPTYSTRING(portnum)) {
char *ep;
long nport;
nport = strtol(portnum, &ep, 10);
if (nport < 1 || nport > 0xffff || *ep != '\0') {
warnx("Invalid port: %s", portnum);
goto cleanup_url_get;
}
port = htons(nport);
port = portnum;
} else
port = httpport;
sin.sin_port = port;
s = socket(AF_INET, SOCK_STREAM, 0);
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(host, port, &hints, &res);
if (error) {
warnx("%s: %s", host, gai_strerror(error));
if (error = EAI_SYSTEM)
warnx("%s: %s", host, strerror(errno));
goto cleanup_url_get;
}
while (1)
{
s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (s == -1) {
warn("Can't create socket");
goto cleanup_url_get;
}
if (dobind && bind(s, (struct sockaddr *)&bindto,
sizeof(bindto)) == -1) {
warn("Can't bind to %s", inet_ntoa(bindto.sin_addr));
((struct sockaddr *)&bindto)->sa_len) == -1) {
getnameinfo((struct sockaddr *)&bindto,
((struct sockaddr *)&bindto)->sa_len,
nameinfo, sizeof(nameinfo), NULL, 0,
NI_NUMERICHOST|NI_WITHSCOPEID);
/* XXX check error? */
warn("Can't bind to %s", nameinfo);
goto cleanup_url_get;
}
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
warn("Can't connect to %s", host);
if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
close(s);
res = res->ai_next;
if (res)
continue;
goto cleanup_url_get;
}
break;
}
/*
* Construct and send the request. We're expecting a return
* status of "200". Proxy requests don't want leading /.
@ -645,3 +655,14 @@ auto_fetch(argc, argv)
disconnect(0, NULL);
return (rval);
}
int
isurl(p)
const char *p;
{
if (strncasecmp(p, FTP_URL, sizeof(FTP_URL) - 1) == 0
|| strncasecmp(p, HTTP_URL, sizeof(HTTP_URL) - 1) == 0) {
return 1;
}
return 0;
}

View File

@ -34,7 +34,7 @@
.\"
.\" @(#)ftp.1 8.3 (Berkeley) 10/9/94
.\"
.Dd August 18, 1997
.Dd January 27, 2000
.Dt FTP 1
.Os BSD 4.2
.Sh NAME
@ -61,6 +61,7 @@ is the user interface to the
standard File Transfer Protocol.
The program allows a user to transfer files to and from a
remote network site.
The version supports IPv6 (Internet protocol version 6), as well as IPv4.
.Pp
The latter three usage formats will fetch a file using either the
HTTP or FTP protocols into the current directory.
@ -682,7 +683,18 @@ through a gateway router or host that controls the directionality of
traffic.
(Note that though ftp servers are required to support the
.Dv PASV
command by RFC 1123, some do not.)
command by RFC 1123, some do not.
Please note that if you are connecting to IPv6 ftp server,
the program will use
.Dv EPSV/EPRT
pair and
.Dv LPSV/LPRT
pair,
instead of
.Dv PASV
and
.Dv PORT .
The meaning is the same.)
.It Ic preserve
Toggle preservation of modification times on retrieved files.
.It Ic progress
@ -1402,6 +1414,8 @@ fetching of files, ftp and http URLs, and modification time
preservation were implemented in
.Nx 1.3
by Luke Mewburn, with assistance from Jason Thorpe.
.Pp
IPv6 support was added by WIDE/KAME Project.
.Sh BUGS
Correct execution of many commands depends upon proper behavior
by the remote server.
@ -1416,3 +1430,7 @@ to and from
.Bx 4.2
servers using the ascii type.
Avoid this problem by using the binary image type.
.Pp
Proxying functionalities, such as
.Ev ftp_proxy ,
may not work for IPv6 connection.

View File

@ -71,68 +71,93 @@ __RCSID_SOURCE("$NetBSD: ftp.c,v 1.29.2.1 1997/11/18 01:01:04 mellon Exp $");
#include "ftp_var.h"
struct sockaddr_in hisctladdr;
struct sockaddr_in data_addr;
/* wrapper for KAME-special getnameinfo() */
#ifndef NI_WITHSCOPEID
#define NI_WITHSCOPEID 0
#endif
extern int h_errno;
int data = -1;
int abrtflag = 0;
jmp_buf ptabort;
int ptabflg;
int ptflag = 0;
struct sockaddr_in myctladdr;
FILE *cin, *cout;
union sockunion {
struct sockinet {
u_char si_len;
u_char si_family;
u_short si_port;
} su_si;
struct sockaddr_in su_sin;
struct sockaddr_in6 su_sin6;
};
#define su_len su_si.si_len
#define su_family su_si.si_family
#define su_port su_si.si_port
union sockunion myctladdr, hisctladdr, data_addr;
char *
hookup(host, port)
const char *host;
int port;
char *port;
{
struct hostent *hp = NULL;
int s, len, tos;
int s, len, tos, error;
struct addrinfo hints, *res, *res0;
static char hostnamebuf[MAXHOSTNAMELEN];
memset((void *)&hisctladdr, 0, sizeof(hisctladdr));
if (inet_aton(host, &hisctladdr.sin_addr) != 0) {
hisctladdr.sin_family = AF_INET;
(void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
} else {
hp = gethostbyname(host);
if (hp == NULL) {
warnx("%s: %s", host, hstrerror(h_errno));
code = -1;
return ((char *) 0);
}
hisctladdr.sin_family = hp->h_addrtype;
memcpy(&hisctladdr.sin_addr, hp->h_addr_list[0],
MIN(hp->h_length,sizeof(hisctladdr.sin_addr)));
(void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
error = getaddrinfo(host, port, &hints, &res0);
if (error) {
warnx("%s: %s", host, gai_strerror(error));
if (error == EAI_SYSTEM)
warnx("%s: %s", host, strerror(errno));
code = -1;
return (0);
}
res = res0;
if (res->ai_canonname)
hostname = res->ai_canonname;
else {
(void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
hostname = hostnamebuf;
}
hostnamebuf[sizeof(hostnamebuf) - 1] = '\0';
hostname = hostnamebuf;
hisctladdr.sin_port = port;
while (1) {
if ((s = socket(hisctladdr.sin_family, SOCK_STREAM, 0)) == -1) {
s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (s < 0) {
warn("socket");
code = -1;
return (0);
}
if (dobind && bind(s, (struct sockaddr *)&bindto,
sizeof(bindto)) == -1) {
if (dobind &&
bind(s, (struct sockaddr *)&bindto,
((struct sockaddr *)&bindto)->sa_len) == -1) {
warn("bind");
code = -1;
goto bad;
goto next;
}
if (connect(s, (struct sockaddr *)&hisctladdr,
sizeof(hisctladdr)) == 0)
if (connect(s, res->ai_addr, res->ai_addrlen) == 0)
break;
if (hp && *++hp->h_addr_list) {
warnc(errno, "connect to address %s",
inet_ntoa(hisctladdr.sin_addr));
memcpy(&hisctladdr.sin_addr, hp->h_addr_list[0],
MIN(hp->h_length,sizeof(hisctladdr.sin_addr)));
printf("Trying %s...\n",
inet_ntoa(hisctladdr.sin_addr));
next:
if (res->ai_next) {
char hname[INET6_ADDRSTRLEN];
getnameinfo(res->ai_addr, res->ai_addrlen,
hname, sizeof(hname) - 1, NULL, 0,
NI_NUMERICHOST|NI_WITHSCOPEID);
warn("connect to address %s", hname);
res = res->ai_next;
getnameinfo(res->ai_addr, res->ai_addrlen,
hname, sizeof(hname) - 1, NULL, 0,
NI_NUMERICHOST|NI_WITHSCOPEID);
printf("Trying %s...\n", hname);
(void)close(s);
continue;
}
@ -140,6 +165,7 @@ hookup(host, port)
code = -1;
goto bad;
}
memcpy(&hisctladdr, res->ai_addr, res->ai_addrlen);
len = sizeof(myctladdr);
if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
warn("getsockname");
@ -147,9 +173,12 @@ hookup(host, port)
goto bad;
}
#ifdef IP_TOS
tos = IPTOS_LOWDELAY;
if (myctladdr.su_family == AF_INET)
{
tos = IPTOS_LOWDELAY;
if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
warn("setsockopt TOS (ignored)");
}
#endif
cin = fdopen(s, "r");
cout = fdopen(s, "w");
@ -324,11 +353,25 @@ getreply(expecteof)
}
if (dig < 4 && isdigit((unsigned char)c))
code = code * 10 + (c - '0');
if (!pflag && code == 227)
pflag = 1;
if (dig > 4 && pflag == 1 && isdigit((unsigned char)c))
switch (pflag) {
case 0:
if (code == 227 || code == 228) {
/* result for PASV/LPSV */
pflag = 1;
/* fall through */
} else if (code == 229) {
/* result for EPSV */
pflag = 1;
pflag = 100;
break;
} else
break;
case 1:
if (!(dig > 4 && isdigit((unsigned char)c)))
break;
pflag = 2;
if (pflag == 2) {
/* fall through */
case 2:
if (c != '\r' && c != ')' &&
pt < &pasv[sizeof(pasv)-1])
*pt++ = c;
@ -336,6 +379,11 @@ getreply(expecteof)
*pt = '\0';
pflag = 3;
}
break;
case 100:
if (dig > 4 && c == '(')
pflag = 2;
break;
}
if (dig == 4 && c == '-') {
if (continuation)
@ -1080,17 +1128,29 @@ initconn()
char *p, *a;
int result, len, tmpno = 0;
int on = 1;
int a0, a1, a2, a3, p0, p1;
int ports;
int error, ports;
u_int af;
u_int hal, h[16];
u_int pal, prt[2];
char *pasvcmd;
#ifdef INET6
if (myctladdr.su_family == AF_INET6
&& (IN6_IS_ADDR_LINKLOCAL(&myctladdr.su_sin6.sin6_addr)
|| IN6_IS_ADDR_SITELOCAL(&myctladdr.su_sin6.sin6_addr))) {
warnx("use of scoped address can be troublesome");
}
#endif
if (passivemode) {
data = socket(AF_INET, SOCK_STREAM, 0);
data_addr = myctladdr;
data = socket(data_addr.su_family, SOCK_STREAM, 0);
if (data < 0) {
warn("socket");
return (1);
}
if (dobind && bind(data, (struct sockaddr *)&bindto,
sizeof(bindto)) == -1) {
((struct sockaddr *)&bindto)->sa_len) == -1) {
warn("bind");
goto bad;
}
@ -1098,47 +1158,166 @@ initconn()
setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
sizeof(on)) < 0)
warn("setsockopt (ignored)");
if (command("PASV") != COMPLETE) {
switch (data_addr.su_family) {
case AF_INET:
result = command(pasvcmd = "EPSV");
if (code / 10 == 22 && code != 229) {
puts("wrong server: return code must be 229");
result = COMPLETE + 1;
}
if (result != COMPLETE)
result = command(pasvcmd = "PASV");
break;
#ifdef INET6
case AF_INET6:
result = command(pasvcmd = "EPSV");
if (code / 10 == 22 && code != 229) {
puts("wrong server: return code must be 229");
result = COMPLETE + 1;
}
if (result != COMPLETE)
result = command(pasvcmd = "LPSV");
break;
#endif
default:
result = COMPLETE + 1;
}
if (result != COMPLETE) {
puts("Passive mode refused.");
goto bad;
}
#define pack2(var, offset) \
(((var[(offset) + 0] & 0xff) << 8) | ((var[(offset) + 1] & 0xff) << 0))
#define pack4(var, offset) \
(((var[(offset) + 0] & 0xff) << 24) | ((var[(offset) + 1] & 0xff) << 16) \
| ((var[(offset) + 2] & 0xff) << 8) | ((var[(offset) + 3] & 0xff) << 0))
/*
* What we've got at this point is a string of comma
* separated one-byte unsigned integer values.
* In PASV case,
* The first four are the an IP address. The fifth is
* the MSB of the port number, the sixth is the LSB.
* From that we'll prepare a sockaddr_in.
* In other case, the format is more complicated.
*/
if (strcmp(pasvcmd, "PASV") == 0) {
if (code / 10 == 22 && code != 227) {
puts("wrong server: return code must be 227");
error = 1;
goto bad;
}
error = sscanf(pasv, "%d,%d,%d,%d,%d,%d",
&h[0], &h[1], &h[2], &h[3],
&prt[0], &prt[1]);
if (error == 6) {
error = 0;
data_addr.su_sin.sin_addr.s_addr =
htonl(pack4(h, 0));
} else
error = 1;
} else if (strcmp(pasvcmd, "LPSV") == 0) {
if (code / 10 == 22 && code != 228) {
puts("wrong server: return code must be 228");
error = 1;
goto bad;
}
switch (data_addr.su_family) {
case AF_INET:
error = sscanf(pasv,
"%d,%d,%d,%d,%d,%d,%d,%d,%d",
&af, &hal,
&h[0], &h[1], &h[2], &h[3],
&pal, &prt[0], &prt[1]);
if (error == 9 && af == 4 && hal == 4 && pal == 2) {
error = 0;
data_addr.su_sin.sin_addr.s_addr =
htonl(pack4(h, 0));
} else
error = 1;
break;
#ifdef INET6
case AF_INET6:
error = sscanf(pasv,
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
&af, &hal,
&h[0], &h[1], &h[2], &h[3],
&h[4], &h[5], &h[6], &h[7],
&h[8], &h[9], &h[10], &h[11],
&h[12], &h[13], &h[14], &h[15],
&pal, &prt[0], &prt[1]);
if (error != 21 || af != 6 || hal != 16 || pal != 2) {
error = 1;
break;
}
if (sscanf(pasv, "%d,%d,%d,%d,%d,%d",
&a0, &a1, &a2, &a3, &p0, &p1) != 6) {
error = 0;
{
u_int32_t *p32;
p32 = (u_int32_t *)&data_addr.su_sin6.sin6_addr;
p32[0] = htonl(pack4(h, 0));
p32[1] = htonl(pack4(h, 4));
p32[2] = htonl(pack4(h, 8));
p32[3] = htonl(pack4(h, 12));
}
break;
#endif
default:
error = 1;
}
} else if (strcmp(pasvcmd, "EPSV") == 0) {
char delim[4];
char *tcpport;
prt[0] = 0;
if (code / 10 == 22 && code != 229) {
puts("wrong server: return code must be 229");
error = 1;
goto bad;
}
error = sscanf(pasv, "%c%c%c%d%c",
&delim[0], &delim[1], &delim[2],
&prt[1], &delim[3]);
if (error != 5) {
error = 1;
goto epsv_done;
}
if (delim[0] != delim[1] || delim[0] != delim[2]
|| delim[0] != delim[3]) {
error = 1;
goto epsv_done;
}
data_addr = hisctladdr;
/* quickhack */
prt[0] = (prt[1] & 0xff00) >> 8;
prt[1] &= 0xff;
error = 0;
epsv_done:
} else
error = 1;
if (error) {
puts(
"Passive mode address scan failure. Shouldn't happen!");
goto bad;
}
};
memset(&data_addr, 0, sizeof(data_addr));
data_addr.sin_family = AF_INET;
a = (char *)&data_addr.sin_addr.s_addr;
a[0] = a0 & 0xff;
a[1] = a1 & 0xff;
a[2] = a2 & 0xff;
a[3] = a3 & 0xff;
p = (char *)&data_addr.sin_port;
p[0] = p0 & 0xff;
p[1] = p1 & 0xff;
data_addr.su_port = htons(pack2(prt, 0));
if (connect(data, (struct sockaddr *)&data_addr,
sizeof(data_addr)) < 0) {
data_addr.su_len) < 0) {
warn("connect");
goto bad;
}
#ifdef IP_TOS
if (data_addr.su_family == AF_INET)
{
on = IPTOS_THROUGHPUT;
if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
sizeof(int)) < 0)
warn("setsockopt TOS (ignored)");
}
#endif
return (0);
}
@ -1146,10 +1325,10 @@ initconn()
noport:
data_addr = myctladdr;
if (sendport)
data_addr.sin_port = 0; /* let system pick one */
data_addr.su_port = 0; /* let system pick one */
if (data != -1)
(void)close(data);
data = socket(AF_INET, SOCK_STREAM, 0);
data = socket(data_addr.su_family, SOCK_STREAM, 0);
if (data < 0) {
warn("socket");
if (tmpno)
@ -1163,12 +1342,27 @@ initconn()
goto bad;
}
#ifdef IP_PORTRANGE
if (data_addr.su_family == AF_INET)
{
ports = restricted_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
if (setsockopt(data, IPPROTO_IP, IP_PORTRANGE, (char *)&ports,
sizeof(ports)) < 0)
warn("setsockopt PORTRANGE (ignored)");
}
#endif
if (bind(data, (struct sockaddr *)&data_addr, sizeof(data_addr)) < 0) {
#ifdef INET6
#ifdef IPV6_PORTRANGE
if (data_addr.su_family == AF_INET6) {
ports = restricted_data_ports ? IPV6_PORTRANGE_HIGH
: IPV6_PORTRANGE_DEFAULT;
if (setsockopt(data, IPPROTO_IPV6, IPV6_PORTRANGE,
(char *)&ports, sizeof(ports)) < 0)
warn("setsockopt PORTRANGE (ignored)");
}
#endif
#endif
if (bind(data, (struct sockaddr *)&data_addr, data_addr.su_len) < 0) {
warn("bind");
goto bad;
}
@ -1184,13 +1378,79 @@ initconn()
if (listen(data, 1) < 0)
warn("listen");
if (sendport) {
a = (char *)&data_addr.sin_addr;
p = (char *)&data_addr.sin_port;
char hname[INET6_ADDRSTRLEN];
int af;
struct sockaddr_in data_addr4;
union sockunion *daddr;
#ifdef INET6
if (data_addr.su_family == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&data_addr.su_sin6.sin6_addr)) {
memset(&data_addr4, 0, sizeof(data_addr4));
data_addr4.sin_len = sizeof(struct sockaddr_in);
data_addr4.sin_family = AF_INET;
data_addr4.sin_port = data_addr.su_port;
memcpy((caddr_t)&data_addr4.sin_addr,
(caddr_t)&data_addr.su_sin6.sin6_addr.s6_addr[12],
sizeof(struct in_addr));
daddr = (union sockunion *)&data_addr4;
} else
#endif
daddr = &data_addr;
#define UC(b) (((int)b)&0xff)
result =
command("PORT %d,%d,%d,%d,%d,%d",
UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
UC(p[0]), UC(p[1]));
switch (daddr->su_family) {
case AF_INET:
#ifdef INET6
case AF_INET6:
#endif
af = (daddr->su_family == AF_INET) ? 1 : 2;
if (getnameinfo((struct sockaddr *)daddr,
daddr->su_len, hname,
sizeof(hname) - 1, NULL, 0,
NI_NUMERICHOST|NI_WITHSCOPEID)) {
result = ERROR;
} else {
result = command("EPRT |%d|%s|%d|",
af, hname, ntohs(daddr->su_port));
}
break;
default:
result = COMPLETE + 1;
break;
}
if (result == COMPLETE)
goto skip_port;
p = (char *)&daddr->su_port;
switch (daddr->su_family) {
case AF_INET:
a = (char *)&daddr->su_sin.sin_addr;
result = command("PORT %d,%d,%d,%d,%d,%d",
UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
UC(p[0]), UC(p[1]));
break;
#ifdef INET6
case AF_INET6:
a = (char *)&daddr->su_sin6.sin6_addr;
result = command(
"LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
6, 16,
UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
UC(a[4]),UC(a[5]),UC(a[6]),UC(a[7]),
UC(a[8]),UC(a[9]),UC(a[10]),UC(a[11]),
UC(a[12]),UC(a[13]),UC(a[14]),UC(a[15]),
2, UC(p[0]), UC(p[1]));
break;
#endif
default:
result = COMPLETE + 1; /* xxx */
}
skip_port:
if (result == ERROR && sendport == -1) {
sendport = 0;
tmpno = 1;
@ -1201,9 +1461,12 @@ initconn()
if (tmpno)
sendport = 1;
#ifdef IP_TOS
if (data_addr.su_family == AF_INET)
{
on = IPTOS_THROUGHPUT;
if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
warn("setsockopt TOS (ignored)");
}
#endif
return (0);
bad:
@ -1217,10 +1480,10 @@ FILE *
dataconn(lmode)
const char *lmode;
{
struct sockaddr_in from;
union sockunion from;
int s, fromlen, tos;
fromlen = sizeof(from);
fromlen = myctladdr.su_len;
if (passivemode)
return (fdopen(data, lmode));
@ -1234,9 +1497,12 @@ dataconn(lmode)
(void)close(data);
data = s;
#ifdef IP_TOS
if (data_addr.su_family == AF_INET)
{
tos = IPTOS_THROUGHPUT;
if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
warn("setsockopt TOS (ignored)");
}
#endif
return (fdopen(data, lmode));
}
@ -1267,8 +1533,8 @@ pswitch(flag)
static struct comvars {
int connect;
char name[MAXHOSTNAMELEN];
struct sockaddr_in mctl;
struct sockaddr_in hctl;
union sockunion mctl;
union sockunion hctl;
FILE *in;
FILE *out;
int tpe;

View File

@ -41,6 +41,7 @@
*/
#include <sys/param.h>
#include <sys/socket.h>
#include <setjmp.h>
#include <stringlist.h>
#include <netinet/in.h>
@ -96,7 +97,7 @@ int preserve; /* preserve modification time on files */
int progress; /* display transfer progress bar */
int code; /* return/reply code for ftp command */
int crflag; /* if 1, strip car. rets. on ascii gets */
char pasv[64]; /* passive port for proxy data connection */
char pasv[BUFSIZ]; /* passive port for proxy data connection */
int passivemode; /* passive mode enabled */
int restricted_data_ports; /* enable quarantine FTP area */
char *altarg; /* argv[1] with no shell-like preprocessing */
@ -138,12 +139,12 @@ char *hostname; /* name of host connected to */
int unix_server; /* server is unix, can use binary for ascii */
int unix_proxy; /* proxy is unix, can use binary for ascii */
u_int16_t ftpport; /* port number to use for ftp connections */
u_int16_t httpport; /* port number to use for http connections */
u_int16_t gateport; /* port number to use for gateftp connections */
char *ftpport; /* port number to use for ftp connections */
char *httpport; /* port number to use for http connections */
char *gateport; /* port number to use for gateftp connections */
int dobind; /* bind to specific address */
struct sockaddr_in bindto; /* address to bind to */
struct sockaddr_storage bindto; /* address to bind to */
jmp_buf toplevel; /* non-local goto stuff for cmd scanner */

View File

@ -58,6 +58,7 @@ __RCSID_SOURCE("$NetBSD: main.c,v 1.26 1997/10/14 16:31:22 christos Exp $");
#include <arpa/inet.h>
#include <err.h>
#include <errno.h>
#include <locale.h>
#include <netdb.h>
#include <pwd.h>
@ -86,33 +87,14 @@ main(argc, argv)
(void) setlocale(LC_ALL, "");
sp = getservbyname("ftp", "tcp");
if (sp == 0)
ftpport = htons(FTP_PORT); /* good fallback */
else
ftpport = sp->s_port;
sp = getservbyname("http", "tcp");
if (sp == 0)
httpport = htons(HTTP_PORT); /* good fallback */
else
httpport = sp->s_port;
gateport = 0;
ftpport = "ftp";
httpport = "http";
gateport = NULL;
cp = getenv("FTPSERVERPORT");
if (cp != NULL) {
port = strtol(cp, &ep, 10);
if (port < 1 || port > 0xffff || *ep != '\0')
warnx("bad FTPSERVERPORT port number: %s (ignored)",
cp);
else
gateport = htons(port);
}
if (gateport == 0) {
sp = getservbyname("ftpgate", "tcp");
if (sp == 0)
gateport = htons(GATE_PORT);
else
gateport = sp->s_port;
}
if (cp != NULL)
gateport = cp;
if (!gateport)
gateport = "ftpgate";
doglob = 1;
interactive = 1;
autologin = 1;
@ -203,11 +185,7 @@ main(argc, argv)
break;
case 'P':
port = strtol(optarg, &ep, 10);
if (port < 1 || port > 0xffff || *ep != '\0')
warnx("bad port number: %s (ignored)", optarg);
else
ftpport = htons(port);
ftpport = optarg;
break;
case 's':
@ -244,17 +222,24 @@ main(argc, argv)
sendport = -1; /* not using ports */
if (dobind) {
memset((void *)&bindto, 0, sizeof(bindto));
if (inet_aton(src_addr, &bindto.sin_addr) == 1)
bindto.sin_family = AF_INET;
else {
struct hostent *hp = gethostbyname(src_addr);
if (hp == NULL)
errx(1, "%s: %s", src_addr, hstrerror(h_errno));
bindto.sin_family = hp->h_addrtype;
memcpy(&bindto.sin_addr, hp->h_addr_list[0],
MIN(hp->h_length,sizeof(bindto.sin_addr)));
struct addrinfo hints;
struct addrinfo *res;
char *ftpdataport = "ftp-data";
int error;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(src_addr, NULL, &hints, &res);
if (error) {
fprintf(stderr, "%s: %s", src_addr,
gai_strerror(error));
if (error == EAI_SYSTEM)
errx(1, "%s", strerror(errno));
exit(1);
}
memcpy(&bindto, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
}
/*
@ -280,7 +265,7 @@ main(argc, argv)
#endif
if (argc > 0) {
if (strchr(argv[0], ':') != NULL) {
if (isurl(argv[0])) {
anonftp = 1; /* Handle "automatic" transfers. */
rval = auto_fetch(argc, argv);
if (rval >= 0) /* -1 == connected and cd-ed */

View File

@ -76,7 +76,7 @@ setpeer(argc, argv)
char *argv[];
{
char *host;
u_int16_t port;
char *port;
if (connected) {
printf("Already connected to %s, use close first.\n",
@ -95,19 +95,8 @@ setpeer(argc, argv)
port = gateport;
else
port = ftpport;
if (argc > 2) {
char *ep;
long nport;
nport = strtol(argv[2], &ep, 10);
if (nport < 1 || nport > 0xffff || *ep != '\0') {
printf("%s: bad port number '%s'.\n", argv[0], argv[2]);
printf("usage: %s host-name [port]\n", argv[0]);
code = -1;
return;
}
port = htons(nport);
}
if (argc > 2)
port = strdup(argv[2]);
if (gatemode) {
if (gateserver == NULL || *gateserver == '\0')

View File

@ -31,6 +31,7 @@
# SUCH DAMAGE.
#
# @(#)Makefile 8.1 (Berkeley) 6/6/93
# $FreeBSD$
#
PROG= telnet
@ -39,11 +40,12 @@ CFLAGS+=-DKLUDGELINEMODE -DUSE_TERMIO #-DAUTHENTICATION -DENCRYPTION
CFLAGS+=-DENV_HACK
CFLAGS+=-DSKEY
CFLAGS+=-I${.CURDIR}/../../lib
CFLAGS+=-DIPSEC -DINET6
#CFLAGS+= -DKRB4
DPADD= ${LIBTERMCAP} ${LIBTELNET}
LDADD= -ltermcap -ltelnet
DPADD= ${LIBTERMCAP} ${LIBTELNET} ${LIBIPSEC}
LDADD= -ltermcap -ltelnet -lipsec
#DPADD+= ${LIBKRB} ${LIBDES}
#LDADD+= -lkrb -ldes

View File

@ -29,6 +29,8 @@
* 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$
*/
#ifndef lint
@ -76,7 +78,7 @@ static char sccsid[] = "@(#)commands.c 8.2 (Berkeley) 12/15/93";
# endif /* vax */
#endif /* !defined(CRAY) && !defined(sysV88) */
#include <netinet/ip.h>
#include <netinet/ip6.h>
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
@ -2094,24 +2096,76 @@ ayt_status()
}
#endif
static const char *
sockaddr_ntop(sa)
struct sockaddr *sa;
{
void *addr;
static char addrbuf[INET6_ADDRSTRLEN];
switch (sa->sa_family) {
case AF_INET:
addr = &((struct sockaddr_in *)sa)->sin_addr;
break;
#ifdef INET6
case AF_INET6:
addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
break;
#endif
default:
return NULL;
}
inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf));
return addrbuf;
}
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
static int
setpolicy(net, res, policy)
int net;
struct addrinfo *res;
char *policy;
{
char *buf;
int level;
int optname;
if (policy == NULL)
return 0;
buf = ipsec_set_policy(policy, strlen(policy));
if (buf == NULL) {
printf("%s\n", ipsec_strerror());
return -1;
}
level = res->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
optname = res->ai_family == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY;
if (setsockopt(net, level, optname, buf, ipsec_get_policylen(buf)) < 0){
perror("setsockopt");
return -1;
}
free(buf);
}
#endif
int
tn(argc, argv)
int argc;
char *argv[];
{
register struct hostent *host = 0;
struct sockaddr_in sin, src_sin;
struct servent *sp = 0;
unsigned long temp;
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
struct sockaddr_storage ss, src_ss;
char *srp = 0, *strrchr();
unsigned long sourceroute(), srlen;
#endif
int proto, opt;
int sourceroute(), srlen;
int srcroute = 0, result;
char *cmd, *hostp = 0, *portp = 0, *user = 0;
char *src_addr = NULL;
struct addrinfo hints, *res;
int error = 0;
/* clear the socket address prior to use */
bzero((char *)&sin, sizeof(sin));
memset((char *)&ss, 0, sizeof(ss));
if (connected) {
printf("?Already connected to %s\n", hostname);
@ -2171,128 +2225,106 @@ tn(argc, argv)
goto usage;
if (src_addr != NULL) {
bzero((char *)&src_sin, sizeof(src_sin));
src_sin.sin_family = AF_INET;
if (!inet_aton(src_addr, &src_sin.sin_addr)) {
host = gethostbyname2(src_addr, AF_INET);
if (host == NULL) {
herror(src_addr);
return 0;
}
if (host->h_length != sizeof(src_sin.sin_addr)) {
fprintf(stderr, "telnet: gethostbyname2: invalid address\n");
return 0;
}
memcpy((void *)&src_sin.sin_addr, (void *)host->h_addr_list[0],
sizeof(src_sin.sin_addr));
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(src_addr, 0, &hints, &res);
if (error == EAI_NONAME) {
hints.ai_flags = 0;
error = getaddrinfo(src_addr, 0, &hints, &res);
}
if (error != 0) {
fprintf(stderr, "%s: %s\n", src_addr, gai_strerror(error));
if (error == EAI_SYSTEM)
fprintf(stderr, "%s: %s\n", src_addr, strerror(errno));
return 0;
}
memcpy((void *)&src_ss, (void *)res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
}
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
if (hostp[0] == '@' || hostp[0] == '!') {
if ((hostname = strrchr(hostp, ':')) == NULL)
if (
#ifdef INET6
family == AF_INET6 ||
#endif
(hostname = strrchr(hostp, ':')) == NULL)
hostname = strrchr(hostp, '@');
hostname++;
srp = 0;
temp = sourceroute(hostp, &srp, &srlen);
if (temp == 0) {
herror(srp);
srcroute = 1;
} else
hostname = hostp;
if (!portp) {
telnetport = 1;
portp = "telnet";
} else if (*portp == '-') {
portp++;
telnetport = 1;
} else
telnetport = 0;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(hostname, portp, &hints, &res);
if (error == 0) {
int gni_err = 1;
if (doaddrlookup)
gni_err = getnameinfo(res->ai_addr, res->ai_addr->sa_len,
_hostname, sizeof(_hostname) - 1, NULL, 0,
0);
if (gni_err != 0)
(void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
_hostname[sizeof(_hostname)-1] = '\0';
hostname = _hostname;
} else if (error == EAI_NONAME) {
hints.ai_flags = AI_CANONNAME;
error = getaddrinfo(hostname, portp, &hints, &res);
if (error != 0) {
fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error));
if (error == EAI_SYSTEM)
fprintf(stderr, "%s: %s\n", hostname, strerror(errno));
setuid(getuid());
return 0;
} else if (temp == -1) {
}
memcpy((void *)&ss, (void *)res->ai_addr, res->ai_addrlen);
if (srcroute != 0)
(void) strncpy(_hostname, hostname, sizeof(_hostname) - 1);
else if (res->ai_canonname != NULL)
strcpy(_hostname, res->ai_canonname);
else
(void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
_hostname[sizeof(_hostname)-1] = '\0';
hostname = _hostname;
}
if (srcroute != 0) {
srp = 0;
result = sourceroute(res, hostp, &srp, &srlen, &proto, &opt);
if (result == 0) {
setuid(getuid());
freeaddrinfo(res);
return 0;
} else if (result == -1) {
printf("Bad source route option: %s\n", hostp);
setuid(getuid());
freeaddrinfo(res);
return 0;
} else {
sin.sin_addr.s_addr = temp;
sin.sin_family = AF_INET;
}
} else {
#endif
temp = inet_addr(hostp);
if (temp != INADDR_NONE) {
sin.sin_addr.s_addr = temp;
sin.sin_family = AF_INET;
if (doaddrlookup)
host = gethostbyaddr((char *)&temp, sizeof(temp), AF_INET);
if (host)
(void) strncpy(_hostname, host->h_name, sizeof(_hostname));
else
(void) strncpy(_hostname, hostp, sizeof(_hostname));
_hostname[sizeof(_hostname)-1] = '\0';
hostname = _hostname;
} else {
host = gethostbyname(hostp);
if (host) {
sin.sin_family = host->h_addrtype;
#if defined(h_addr) /* In 4.3, this is a #define */
memmove((caddr_t)&sin.sin_addr,
host->h_addr_list[0],
MIN(host->h_length, sizeof(sin.sin_addr)));
#else /* defined(h_addr) */
memmove((caddr_t)&sin.sin_addr, host->h_addr,
MIN(host->h_length, sizeof(sin.sin_addr)));
#endif /* defined(h_addr) */
strncpy(_hostname, host->h_name, sizeof(_hostname));
_hostname[sizeof(_hostname)-1] = '\0';
hostname = _hostname;
} else {
herror(hostp);
setuid(getuid());
return 0;
}
}
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
}
#endif
if (portp) {
if (*portp == '-') {
portp++;
telnetport = 1;
} else
telnetport = 0;
sin.sin_port = atoi(portp);
if (sin.sin_port == 0) {
sp = getservbyname(portp, "tcp");
if (sp)
sin.sin_port = sp->s_port;
else {
printf("%s: bad port number\n", portp);
setuid(getuid());
return 0;
}
} else {
#if !defined(htons)
u_short htons P((unsigned short));
#endif /* !defined(htons) */
sin.sin_port = htons(sin.sin_port);
}
} else {
if (sp == 0) {
sp = getservbyname("telnet", "tcp");
if (sp == 0) {
fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
setuid(getuid());
return 0;
}
sin.sin_port = sp->s_port;
}
telnetport = 1;
}
printf("Trying %s...\n", inet_ntoa(sin.sin_addr));
printf("Trying %s...\n", sockaddr_ntop(res->ai_addr));
do {
net = socket(AF_INET, SOCK_STREAM, 0);
net = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
setuid(getuid());
if (net < 0) {
perror("telnet: socket");
return 0;
}
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
perror("setsockopt (IP_OPTIONS)");
#endif
if (srp && setsockopt(net, proto, opt, (char *)srp, srlen) < 0)
perror("setsockopt (source route)");
#if defined(IPPROTO_IP) && defined(IP_TOS)
{
if (res->ai_family == PF_INET) {
# if defined(HAS_GETTOS)
struct tosent *tp;
if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
@ -2313,28 +2345,31 @@ tn(argc, argv)
}
if (src_addr != NULL) {
if (bind(net, (struct sockaddr *)&src_sin, sizeof(src_sin)) == -1) {
if (bind(net, (struct sockaddr *)&src_ss,
((struct sockaddr *)&src_ss)->sa_len) == -1) {
perror("bind");
return 0;
}
}
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
if (setpolicy(net, res, ipsec_policy_in) < 0)
return 0;
if (setpolicy(net, res, ipsec_policy_out) < 0)
return 0;
#endif
if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
#if defined(h_addr) /* In 4.3, this is a #define */
if (host && host->h_addr_list[1]) {
if (connect(net, res->ai_addr, res->ai_addrlen) < 0) {
if (res->ai_next) {
int oerrno = errno;
fprintf(stderr, "telnet: connect to address %s: ",
inet_ntoa(sin.sin_addr));
sockaddr_ntop(res->ai_addr));
errno = oerrno;
perror((char *)0);
host->h_addr_list++;
memcpy((caddr_t)&sin.sin_addr, host->h_addr_list[0],
MIN(host->h_length, sizeof(sin.sin_addr)));
res = res->ai_next;
(void) NetClose(net);
continue;
}
#endif /* defined(h_addr) */
perror("telnet: Unable to connect to remote host");
return 0;
}
@ -2343,6 +2378,7 @@ tn(argc, argv)
auth_encrypt_connect(connected);
#endif /* defined(AUTHENTICATION) */
} while (connected == 0);
freeaddrinfo(res);
cmdrc(hostp, hostname);
if (autologin && user == NULL) {
struct passwd *pw;
@ -2681,8 +2717,6 @@ cmdrc(m1, m2)
fclose(rcfile);
}
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
/*
* Source route is handed in as
* [!]@hop1@hop2...[@|:]dst
@ -2696,6 +2730,10 @@ cmdrc(m1, m2)
* be the address to connect() to.
*
* Arguments:
*
* res: ponter to addrinfo structure which contains sockaddr to
* the host to connect to.
*
* arg: pointer to route list to decipher
*
* cpp: If *cpp is not equal to NULL, this is a
@ -2705,9 +2743,18 @@ cmdrc(m1, m2)
* lenp: pointer to an integer that contains the
* length of *cpp if *cpp != NULL.
*
* protop: pointer to an integer that should be filled in with
* appropriate protocol for setsockopt, as socket
* protocol family.
*
* optp: pointer to an integer that should be filled in with
* appropriate option for setsockopt, as socket protocol
* family.
*
* Return values:
*
* Returns the address of the host to connect to. If the
* If the return value is 1, then all operations are
* successful. If the
* return value is -1, there was a syntax error in the
* option, either unknown characters, or too many hosts.
* If the return value is 0, one of the hostnames in the
@ -2721,21 +2768,32 @@ cmdrc(m1, m2)
* *lenp: This will be filled in with how long the option
* pointed to by *cpp is.
*
* *protop: This will be filled in with appropriate protocol for
* setsockopt, as socket protocol family.
*
* *optp: This will be filled in with appropriate option for
* setsockopt, as socket protocol family.
*/
unsigned long
sourceroute(arg, cpp, lenp)
int
sourceroute(ai, arg, cpp, lenp, protop, optp)
struct addrinfo *ai;
char *arg;
char **cpp;
int *lenp;
int *protop;
int *optp;
{
static char lsr[44];
static char buf[1024]; /*XXX*/
struct cmsghdr *cmsg;
#ifdef sysV88
static IOPTN ipopt;
#endif
char *cp, *cp2, *lsrp, *lsrep;
char *cp, *cp2, *lsrp, *ep;
register int tmp;
struct in_addr sin_addr;
register struct hostent *host = 0;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
struct addrinfo hints, *res;
int error;
register char c;
/*
@ -2744,22 +2802,46 @@ sourceroute(arg, cpp, lenp)
*/
if (cpp == NULL || lenp == NULL)
return((unsigned long)-1);
if (*cpp != NULL && *lenp < 7)
return((unsigned long)-1);
if (*cpp != NULL) {
switch (res->ai_family) {
case AF_INET:
if (*lenp < 7)
return((unsigned long)-1);
break;
#ifdef INET6
case AF_INET6:
if (*lenp < (sizeof(struct cmsghdr) +
sizeof(struct ip6_rthdr) +
sizeof(struct in6_addr)))
return((unsigned long)-1);
break;
#endif
}
}
/*
* Decide whether we have a buffer passed to us,
* or if we need to use our own static buffer.
*/
if (*cpp) {
lsrp = *cpp;
lsrep = lsrp + *lenp;
ep = lsrp + *lenp;
} else {
*cpp = lsrp = lsr;
lsrep = lsrp + 44;
*cpp = lsrp = buf;
ep = lsrp + 1024;
}
cp = arg;
#ifdef INET6
if (ai->ai_family == AF_INET6) {
cmsg = inet6_rthdr_init(*cpp, IPV6_RTHDR_TYPE_0);
if (*cp != '@')
return -1;
*protop = IPPROTO_IPV6;
*optp = IPV6_PKTOPTIONS;
} else
#endif
{
/*
* Next, decide whether we have a loose source
* route or a strict source route, and fill in
@ -2786,13 +2868,20 @@ sourceroute(arg, cpp, lenp)
lsrp++; /* skip over length, we'll fill it in later */
*lsrp++ = 4;
#endif
*protop = IPPROTO_IP;
*optp = IP_OPTIONS;
}
cp++;
sin_addr.s_addr = 0;
memset(&hints, 0, sizeof(hints));
hints.ai_family = ai->ai_family;
hints.ai_socktype = SOCK_STREAM;
for (c = 0;;) {
if (c == ':')
if (
#ifdef INET6
ai->ai_family != AF_INET6 &&
#endif
c == ':')
cp2 = 0;
else for (cp2 = cp; c = *cp2; cp2++) {
if (c == ',') {
@ -2801,7 +2890,11 @@ sourceroute(arg, cpp, lenp)
cp2++;
} else if (c == '@') {
*cp2++ = '\0';
} else if (c == ':') {
} else if (
#ifdef INET6
ai->ai_family != AF_INET6 &&
#endif
c == ':') {
*cp2++ = '\0';
} else
continue;
@ -2810,22 +2903,32 @@ sourceroute(arg, cpp, lenp)
if (!c)
cp2 = 0;
if ((tmp = inet_addr(cp)) != -1) {
sin_addr.s_addr = tmp;
} else if (host = gethostbyname(cp)) {
#if defined(h_addr)
memcpy((caddr_t)&sin_addr, host->h_addr_list[0],
MIN(host->h_length,sizeof(sin_addr)));
#else
memcpy((caddr_t)&sin_addr, host->h_addr,
MIN(host->h_length,sizeof(sin_addr)));
#endif
} else {
hints.ai_flags = AI_NUMERICHOST;
error = getaddrinfo(cp, NULL, &hints, &res);
if (error == EAI_NONAME) {
hints.ai_flags = 0;
error = getaddrinfo(cp, NULL, &hints, &res);
}
if (error != 0) {
fprintf(stderr, "%s: %s\n", cp, gai_strerror(error));
if (error == EAI_SYSTEM)
fprintf(stderr, "%s: %s\n", cp,
strerror(errno));
*cpp = cp;
return(0);
}
memcpy(lsrp, (char *)&sin_addr, 4);
#ifdef INET6
if (res->ai_family == AF_INET6) {
sin6 = (struct sockaddr_in6 *)res->ai_addr;
inet6_rthdr_add(cmsg, &sin6->sin6_addr,
IPV6_RTHDR_LOOSE);
} else
#endif
{
sin = (struct sockaddr_in *)res->ai_addr;
memcpy(lsrp, (char *)&sin->sin_addr, 4);
lsrp += 4;
}
if (cp2)
cp = cp2;
else
@ -2833,9 +2936,27 @@ sourceroute(arg, cpp, lenp)
/*
* Check to make sure there is space for next address
*/
if (lsrp + 4 > lsrep)
#ifdef INET6
if (res->ai_family == AF_INET6) {
if (((char *)cmsg +
sizeof(struct cmsghdr) +
sizeof(struct ip6_rthdr) +
((inet6_rthdr_segments(cmsg) + 1) *
sizeof(struct in6_addr))) > ep)
return((unsigned long)-1);
} else
#endif
if (lsrp + 4 > ep)
return((unsigned long)-1);
freeaddrinfo(res);
}
#ifdef INET6
if (res->ai_family == AF_INET6) {
inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
*lenp = cmsg->cmsg_len;
} else
#endif
{
#ifndef sysV88
if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
*cpp = 0;
@ -2854,6 +2975,7 @@ sourceroute(arg, cpp, lenp)
*lenp = sizeof(ipopt);
*cpp = (char *) &ipopt;
#endif
return(sin_addr.s_addr);
}
freeaddrinfo(res);
return 1;
}
#endif

View File

@ -31,6 +31,7 @@
* SUCH DAMAGE.
*
* @(#)externs.h 8.2 (Berkeley) 12/15/93
* $FreeBSD$
*/
#ifndef BSD
@ -86,6 +87,14 @@ typedef unsigned char cc_t;
#endif
#include <strings.h>
#if defined(IPSEC)
#include <netinet6/ipsec.h>
#if defined(IPSEC_POLICY_IPSEC)
extern char *ipsec_policy_in;
extern char *ipsec_policy_out;
#endif
#endif
#ifndef _POSIX_VDISABLE
# ifdef sun
# include <sys/param.h> /* pick up VDISABLE definition, mayby */
@ -115,6 +124,7 @@ extern int
autologin, /* Autologin enabled */
skiprc, /* Don't process the ~/.telnetrc file */
eight, /* use eight bit mode (binary in and/or out */
family, /* address family of peer */
flushout, /* flush output */
connected, /* Are we connected to the other side? */
globalmode, /* Mode tty should be in */

View File

@ -29,6 +29,8 @@
* 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$
*/
#ifndef lint
@ -42,6 +44,7 @@ static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 12/15/93";
#endif /* not lint */
#include <sys/types.h>
#include <sys/socket.h>
#include "ring.h"
#include "externs.h"
@ -56,6 +59,13 @@ static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 12/15/93";
#define FORWARD
#endif
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
char *ipsec_policy_in = NULL;
char *ipsec_policy_out = NULL;
#endif
int family = AF_UNSPEC;
/*
* Initialize variables.
*/
@ -81,10 +91,10 @@ usage()
fprintf(stderr, "Usage: %s %s%s%s%s\n",
prompt,
#ifdef AUTHENTICATION
"[-8] [-E] [-K] [-L] [-N] [-S tos] [-X atype] [-a] [-c] [-d]",
"[-4] [-6] [-8] [-E] [-K] [-L] [-N] [-S tos] [-X atype] [-a] [-c] [-d]",
"\n\t[-e char] [-k realm] [-l user] [-f/-F] [-n tracefile] ",
#else
"[-8] [-E] [-L] [-N] [-S tos] [-a] [-c] [-d] [-e char] [-l user]",
"[-4] [-6] [-8] [-E] [-L] [-N] [-S tos] [-a] [-c] [-d] [-e char] [-l user]",
"\n\t[-n tracefile] ",
#endif
#if defined(TN3270) && defined(unix)
@ -97,6 +107,9 @@ usage()
# endif
#else
"[-r] [-s src_addr] ",
#endif
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
"[-P policy]"
#endif
"[host-name [port]]"
);
@ -138,8 +151,25 @@ main(argc, argv)
rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE;
autologin = -1;
while ((ch = getopt(argc, argv, "8EKLNS:X:acde:fFk:l:n:rs:t:x")) != -1) {
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
#define IPSECOPT "P:"
#else
#define IPSECOPT
#endif
while ((ch = getopt(argc, argv,
"468EKLNS:X:acde:fFk:l:n:rs:t:x" IPSECOPT)) != -1)
#undef IPSECOPT
{
switch(ch) {
case '4':
family = AF_INET;
break;
#ifdef INET6
case '6':
family = AF_INET6;
break;
#endif
case '8':
eight = 3; /* binary output and input */
break;
@ -276,6 +306,16 @@ main(argc, argv)
"%s: Warning: -x ignored, no ENCRYPT support.\n",
prompt);
break;
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
case 'P':
if (!strncmp("in", optarg, 2))
ipsec_policy_in = strdup(optarg);
else if (!strncmp("out", optarg, 3))
ipsec_policy_out = strdup(optarg);
else
usage();
break;
#endif
case '?':
default:
usage();

View File

@ -32,7 +32,7 @@
.\" @(#)telnet.1 8.5 (Berkeley) 3/1/94
.\" $FreeBSD$
.\"
.Dd March 1, 1994
.Dd January 27, 2000
.Dt TELNET 1
.Os BSD 4.2
.Sh NAME
@ -564,9 +564,10 @@ will attempt to contact a
.Tn TELNET
server at the default port.
The host specification may be either a host name (see
.Xr hosts 5 )
or an Internet address specified in the \*(Lqdot notation\*(Rq (see
.Xr inet 3 ) .
.Xr hosts 5 ) ,
an Internet address specified in the \*(Lqdot notation\*(Rq (see
.Xr inet 3 ) ,
or IPv6 host name or IPv6 coloned-hexadecimal addreess.
The
.Fl l
option may be used to specify the user name
@ -1390,6 +1391,8 @@ The
.Nm
command appeared in
.Bx 4.2 .
.Pp
IPv6 support was added by WIDE/KAME project.
.Sh NOTES
.Pp
On some remote systems, echo has to be turned off manually when in

View File

@ -24,6 +24,7 @@ SUBDIR= IPXrouted \
dev_mkdb \
diskpart \
edquota \
faithd \
fdcontrol \
fdformat \
fdwrite \

24
usr.sbin/faithd/Makefile Normal file
View File

@ -0,0 +1,24 @@
# Copyright (c) 1996 WIDE Project. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modifications, are permitted provided that the above copyright notice
# and this paragraph are duplicated in all such forms and that any
# documentation, advertising materials, and other materials related to
# such distribution and use acknowledge that the software was developed
# by the WIDE Project, Japan. The name of the Project may not be used to
# endorse or promote products derived from this software without
# specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS''
# AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
# LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE.
# $FreeBSD$
PROG= faithd
SRCS= faithd.c tcp.c ftp.c rsh.c
MAN8= faithd.8
#CFLAGS+= -DFAITH4
CFLAGS+= -Wall
DPADD+= ${LIBUTIL}
LDADD+= -lutil
.include <bsd.prog.mk>

140
usr.sbin/faithd/README Normal file
View File

@ -0,0 +1,140 @@
Configuring FAITH IPv6-to-IPv4 TCP relay
Kazu Yamamoto and Jun-ichiro itojun Hagino
$Id: README,v 1.1.1.1 1999/08/08 23:29:27 itojun Exp $
$FreeBSD$
Introduction
============
FAITH is a IPv6-to-IPv4 TCP relay. It performs tcp relay just as some of
firewall-oriented gateway does, but between IPv6 and IPv4 with address
translation.
TCP connections has to be made from IPv6 node to IPv4 node. FAITH will
not relay connections for the opposite direction.
To perform relays, FAITH daemon needs to be executed on a router between
your local IPv6 site and outside IPv4 network. The daemon needs to be
invoked per each TCP services (TCP port number).
IPv4 node "dest" = 123.4.5.6
|
[[[[ outside IPv4 ocean ]]]]
|
node that runs FAITH-daemon (usually a router)
|
==+=====+===+==== IPv6, or IPv4/v6 network in your site ^
| | | connection
clients IPv6 node "src" |
You will have to allocate an IPv6 address prefix to map IPv4 addresses into.
The following description uses 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 ssh
<<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 of
KAME package. KAME package is obtained from www.kame.net.
(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.freebsd.org:
3ffe:0501:1234:ffff::204.216.27.21 www.freebsd.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

256
usr.sbin/faithd/faithd.8 Normal file
View File

@ -0,0 +1,256 @@
.\" 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.
.\"
.\" $Id: faithd.8,v 1.3 1999/10/07 04:22:14 itojun Exp $
.\" $FreeBSD$
.\"
.Dd January 27, 2000
.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 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
.Po
should this be configurable?
.Pc .
.\"
.Sh EXAMPLES
Before invoking
.Nm faithd ,
.Xr faith 4
interface has to be configured properly.
.Pp
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
.Pa /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 faith 4 ,
.Xr route 8 ,
.Xr sysctl 8
.Rs
.%A Jun-ichiro itojun Hagino
.%A Kazu Yamamoto
.%T "An IPv6-to-IPv4 transport relay translator"
.%R internet draft
.%N draft-ietf-ngtrans-tcpudp-relay-00.txt
.%O work in progress material
.Re
.\"
.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.

837
usr.sbin/faithd/faithd.c Normal file
View File

@ -0,0 +1,837 @@
/*
* 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$
*/
/*
* User level translator from IPv6 to IPv4.
*
* Usage: faithd [<port> <progpath> <arg1(progname)> <arg2> ...]
* e.g. faithd telnet /usr/local/v6/sbin/telnetd telnetd
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <libutil.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <termios.h>
#include <net/if_types.h>
#ifdef IFT_FAITH
# define USE_ROUTE
# include <net/if.h>
# include <net/route.h>
# include <net/if_dl.h>
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#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];
char procname[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));
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();
#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) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
if (error == EAI_SYSTEM)
exit_error("getaddrinfo: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
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(IPV6_FAITH): %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(IP_FAITH): %s", ERRSTR);
}
#endif
#endif /* FAITH4 */
error = setsockopt(s_wld, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (error == -1)
exit_error("setsockopt(SO_REUSEADDR): %s", ERRSTR);
error = setsockopt(s_wld, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on));
if (error == -1)
exit_error("setsockopt(SO_OOBINLINE): %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();
snprintf(logname, sizeof(logname), "faithd %s", service);
snprintf(procname, sizeof(procname), "accepting port %s", service);
openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
syslog(LOG_INFO, "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(procname);
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;
struct sockaddr *sa4;
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, 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
*/
switch (((struct sockaddr *)&dstaddr6)->sa_family) {
case 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");
break;
#ifdef FAITH4
case 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");
break;
#endif
default:
close(s_src);
exit_error("family not supported");
/*NOTREACHED*/
}
sa4 = (struct sockaddr *)&dstaddr4;
getnameinfo(sa4, sa4->sa_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 (sa4->sa_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, 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;
}
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(SO_OOBINLINE): %s", ERRSTR);
error = setsockopt(s_src, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
if (error == -1)
exit_error("setsockopt(SO_SNDTIMEO): %s", ERRSTR);
error = setsockopt(s_dst, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
if (error == -1)
exit_error("setsockopt(SO_SNDTIMEO): %s", ERRSTR);
error = connect(s_dst, sa4, sa4->sa_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 (memcmp(dst, &faith_prefix,
sizeof(struct in6_addr) - sizeof(struct in_addr) == 0) {
return 1;
}
return 0;
#else
struct myaddrs *p;
struct sockaddr_in6 *sin6;
struct sockaddr_in *sin4;
struct sockaddr_in6 *dst6;
struct sockaddr_in *dst4;
struct sockaddr_in dstmap;
dst6 = (struct sockaddr_in6 *)dst;
if (dst->sa_family == AF_INET6
&& IN6_IS_ADDR_V4MAPPED(&dst6->sin6_addr)) {
/* ugly... */
memset(&dstmap, 0, sizeof(dstmap));
dstmap.sin_family = AF_INET;
dstmap.sin_len = sizeof(dstmap);
memcpy(&dstmap.sin_addr, &dst6->sin6_addr.s6_addr[12],
sizeof(dstmap.sin_addr));
dst = (struct sockaddr *)&dstmap;
}
dst6 = (struct sockaddr_in6 *)dst;
dst4 = (struct sockaddr_in *)dst;
for (p = myaddrs; p; p = p->next) {
sin6 = (struct sockaddr_in6 *)p->addr;
sin4 = (struct sockaddr_in *)p->addr;
if (p->addr->sa_len != dst->sa_len
|| p->addr->sa_family != dst->sa_family)
continue;
switch (dst->sa_family) {
case AF_INET6:
if (sin6->sin6_scope_id == dst6->sin6_scope_id
&& IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &dst6->sin6_addr))
return 0;
break;
case AF_INET:
if (sin4->sin_addr.s_addr == dst4->sin_addr.s_addr)
return 0;
break;
}
}
return 1;
#endif
}
/* 0: non faith, 1: faith */
static int
map6to4(struct sockaddr_in6 *dst6, struct sockaddr_in *dst4)
{
memset(dst4, 0, sizeof(*dst4));
dst4->sin_len = sizeof(*dst4);
dst4->sin_family = AF_INET;
dst4->sin_port = dst6->sin6_port;
memcpy(&dst4->sin_addr, &dst6->sin6_addr.s6_addr[12],
sizeof(dst4->sin_addr));
if (dst4->sin_addr.s_addr == INADDR_ANY
|| dst4->sin_addr.s_addr == INADDR_BROADCAST
|| IN_MULTICAST(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));
if (ai_errno == EAI_SYSTEM)
syslog(LOG_INFO, "%s %s: %s", host, serv,
strerror(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);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
fprintf(stderr, "%s\n", buf);
exit(EXIT_FAILURE);
}
void
exit_failure(const char *fmt, ...)
{
va_list ap;
char buf[BUFSIZ];
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
syslog(LOG_ERR, buf);
exit(EXIT_FAILURE);
}
void
exit_success(const char *fmt, ...)
{
va_list ap;
char buf[BUFSIZ];
va_start(ap, fmt);
vsnprintf(buf, sizeof(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(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
sin6->sin6_addr.s6_addr[2] = 0;
sin6->sin6_addr.s6_addr[3] = 0;
}
}
#endif
myaddrs = p;
if (dflag) {
char hbuf[NI_MAXHOST];
getnameinfo(p->addr, p->addr->sa_len,
hbuf, sizeof(hbuf), NULL, 0,
NI_NUMERICHOST);
syslog(LOG_INFO, "my interface: %s %s", hbuf, 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);
}

70
usr.sbin/faithd/faithd.h Normal file
View File

@ -0,0 +1,70 @@
/*
* 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$
*/
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*/

1139
usr.sbin/faithd/ftp.c Normal file

File diff suppressed because it is too large Load Diff

210
usr.sbin/faithd/rsh.c Normal file
View File

@ -0,0 +1,210 @@
/*
* 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, 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;
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", 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);
}

300
usr.sbin/faithd/tcp.c Normal file
View File

@ -0,0 +1,300 @@
/*
* 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 <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 */
}
}

View File

@ -0,0 +1,312 @@
# faithd, ruby version. requires v6-enabled ruby.
#
# 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 $
# $FreeBSD$
require "socket"
require "thread"
# XXX should be derived from system headers
IPPROTO_IPV6 = 41
IPV6_FAITH = 29
DEBUG = true
DEBUG_LOOPBACK = true
# TODO: OOB data handling
def tcpcopy(s1, s2, m)
STDERR.print "tcpcopy #{s1} #{s2}\n" if DEBUG
buf = ""
while TRUE
begin
buf = s1.sysread(100)
s2.syswrite(buf)
rescue EOFError
break
rescue IOError
break
end
end
STDERR.print "tcpcopy #{s1} #{s2} finished\n" if DEBUG
s1.shutdown(0)
s2.shutdown(1)
end
def relay_ftp_passiveconn(s6, s4, dport6, dport4)
Thread.start do
d6 = TCPserver.open("::", dport6).accept
d4 = TCPsocket.open(s4.getpeer[3], dport4)
t = []
t[0] = Thread.start do
tcpcopy(d6, d4)
end
t[1] = Thread.start do
tcpcopy(d4, d6)
end
for i in t
i.join
end
d4.close
d6.close
end
end
def ftp_parse_2428(line)
if (line[0] != line[line.length - 1])
return nil
end
t = line.split(line[0 .. 0]) # as string
if (t.size != 4 || t[1] !~ /^[12]$/ || t[3] !~ /^\d+$/)
return nil
end
return t[1 .. 3]
end
def relay_ftp_command(s6, s4, state)
STDERR.print "relay_ftp_command start\n" if DEBUG
while TRUE
begin
STDERR.print "s6.gets\n" if DEBUG
line = s6.gets
STDERR.print "line is #{line}\n" if DEBUG
if line == nil
return nil
end
# translate then copy
STDERR.print "line is #{line}\n" if DEBUG
if (line =~ /^EPSV\r\n/i)
STDERR.print "EPSV -> PASV\n" if DEBUG
line = "PASV\n"
state = "EPSV"
elsif (line =~ /^EPRT\s+(.+)\r\n/i)
t = ftp_parse_2428($1)
if t == nil
s6.puts "501 illegal parameter to EPRT\r\n"
next
end
# some tricks should be here
s6.puts "501 illegal parameter to EPRT\r\n"
next
end
STDERR.print "fail: send #{line} as is\n" if DEBUG
s4.puts(line)
break
rescue EOFError
return nil
rescue IOError
return nil
end
end
STDERR.print "relay_ftp_command finish\n" if DEBUG
return state
end
def relay_ftp_status(s4, s6, state)
STDERR.print "relay_ftp_status start\n" if DEBUG
while TRUE
begin
line = s4.gets
if line == nil
return nil
end
# translate then copy
s6.puts(line)
next if line =~ /^\d\d\d-/
next if line !~ /^\d/
# special post-processing
case line
when /^221 / # result to QUIT
s4.shutdown(0)
s6.shutdown(1)
end
break if (line =~ /^\d\d\d /)
rescue EOFError
return nil
rescue IOError
return nil
end
end
STDERR.print "relay_ftp_status finish\n" if DEBUG
return state
end
def relay_ftp(sock, name)
STDERR.print "relay_ftp(#{sock}, #{name})\n" if DEBUG
while TRUE
STDERR.print "relay_ftp(#{sock}, #{name}) accepting\n" if DEBUG
s = sock.accept
STDERR.print "relay_ftp(#{sock}, #{name}) accepted #{s}\n" if DEBUG
Thread.start do
threads = []
STDERR.print "accepted #{s} -> #{Thread.current}\n" if DEBUG
s6 = s
dest6 = s.addr[3]
if !DEBUG_LOOPBACK
t = s.getsockname.unpack("x8 x12 C4")
dest4 = "#{t[0]}.#{t[1]}.#{t[2]}.#{t[3]}"
port4 = s.addr[1]
else
dest4 = "127.0.0.1"
port4 = "ftp"
end
if DEBUG
STDERR.print "IPv6 dest: #{dest6} IPv4 dest: #{dest4}\n" if DEBUG
end
STDERR.print "connect to #{dest4} #{port4}\n" if DEBUG
s4 = TCPsocket.open(dest4, port4)
STDERR.print "connected to #{dest4} #{port4}, #{s4.addr[1]}\n" if DEBUG
state = 0
while TRUE
# translate status line
state = relay_ftp_status(s4, s6, state)
break if state == nil
# translate command line
state = relay_ftp_command(s6, s4, state)
break if state == nil
end
STDERR.print "relay_ftp(#{sock}, #{name}) closing s4\n" if DEBUG
s4.close
STDERR.print "relay_ftp(#{sock}, #{name}) closing s6\n" if DEBUG
s6.close
STDERR.print "relay_ftp(#{sock}, #{name}) done\n" if DEBUG
end
end
STDERR.print "relay_ftp(#{sock}, #{name}) finished\n" if DEBUG
end
def relay_tcp(sock, name)
STDERR.print "relay_tcp(#{sock}, #{name})\n" if DEBUG
while TRUE
STDERR.print "relay_tcp(#{sock}, #{name}) accepting\n" if DEBUG
s = sock.accept
STDERR.print "relay_tcp(#{sock}, #{name}) accepted #{s}\n" if DEBUG
Thread.start do
threads = []
STDERR.print "accepted #{s} -> #{Thread.current}\n" if DEBUG
s6 = s
dest6 = s.addr[3]
if !DEBUG_LOOPBACK
t = s.getsockname.unpack("x8 x12 C4")
dest4 = "#{t[0]}.#{t[1]}.#{t[2]}.#{t[3]}"
port4 = s.addr[1]
else
dest4 = "127.0.0.1"
port4 = "telnet"
end
if DEBUG
STDERR.print "IPv6 dest: #{dest6} IPv4 dest: #{dest4}\n" if DEBUG
end
STDERR.print "connect to #{dest4} #{port4}\n" if DEBUG
s4 = TCPsocket.open(dest4, port4)
STDERR.print "connected to #{dest4} #{port4}, #{s4.addr[1]}\n" if DEBUG
[0, 1].each do |i|
threads[i] = Thread.start do
if (i == 0)
tcpcopy(s6, s4)
else
tcpcopy(s4, s6)
end
end
end
STDERR.print "relay_tcp(#{sock}, #{name}) wait\n" if DEBUG
for i in threads
STDERR.print "relay_tcp(#{sock}, #{name}) wait #{i}\n" if DEBUG
i.join
STDERR.print "relay_tcp(#{sock}, #{name}) wait #{i} done\n" if DEBUG
end
STDERR.print "relay_tcp(#{sock}, #{name}) closing s4\n" if DEBUG
s4.close
STDERR.print "relay_tcp(#{sock}, #{name}) closing s6\n" if DEBUG
s6.close
STDERR.print "relay_tcp(#{sock}, #{name}) done\n" if DEBUG
end
end
STDERR.print "relay_tcp(#{sock}, #{name}) finished\n" if DEBUG
end
def usage()
STDERR.print "usage: #{$0} [-f] port...\n"
end
#------------------------------------------------------------
$mode = "tcp"
while ARGV[0] =~ /^-/ do
case ARGV[0]
when /^-f/
$mode = "ftp"
else
usage()
exit 0
end
ARGV.shift
end
if ARGV.length == 0
usage()
exit 1
end
ftpport = Socket.getservbyname("ftp")
res = []
for port in ARGV
t = Socket.getaddrinfo(nil, port, Socket::PF_INET6, Socket::SOCK_STREAM,
nil, Socket::AI_PASSIVE)
if (t.size <= 0)
STDERR.print "FATAL: getaddrinfo failed (port=#{port})\n"
exit 1
end
res += t
end
sockpool = []
names = []
listenthreads = []
res.each do |i|
s = TCPserver.new(i[3], i[1])
n = Socket.getnameinfo(s.getsockname, Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV).join(" port ")
if i[6] == IPPROTO_IPV6
s.setsockopt(i[6], IPV6_FAITH, 1)
end
s.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
sockpool.push s
names.push n
end
if DEBUG
(0 .. sockpool.size - 1).each do |i|
STDERR.print "listen[#{i}]: #{sockpool[i]} #{names[i]}\n" if DEBUG
end
end
(0 .. sockpool.size - 1).each do |i|
listenthreads[i] = Thread.start do
if DEBUG
STDERR.print "listen[#{i}]: thread #{Thread.current}\n" if DEBUG
end
STDERR.print "listen[#{i}]: thread #{Thread.current}\n" if DEBUG
case $mode
when "tcp"
relay_tcp(sockpool[i], names[i])
when "ftp"
relay_ftp(sockpool[i], names[i])
end
end
end
for i in listenthreads
i.join
end
exit 0