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:
parent
404d72b9f6
commit
4dd8b5ab79
@ -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
|
||||
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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';
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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';
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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')
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -24,6 +24,7 @@ SUBDIR= IPXrouted \
|
||||
dev_mkdb \
|
||||
diskpart \
|
||||
edquota \
|
||||
faithd \
|
||||
fdcontrol \
|
||||
fdformat \
|
||||
fdwrite \
|
||||
|
24
usr.sbin/faithd/Makefile
Normal file
24
usr.sbin/faithd/Makefile
Normal 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
140
usr.sbin/faithd/README
Normal 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
256
usr.sbin/faithd/faithd.8
Normal 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
837
usr.sbin/faithd/faithd.c
Normal 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
70
usr.sbin/faithd/faithd.h
Normal 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
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
210
usr.sbin/faithd/rsh.c
Normal 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
300
usr.sbin/faithd/tcp.c
Normal 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 */
|
||||
}
|
||||
}
|
312
usr.sbin/faithd/test/faithd.rb
Normal file
312
usr.sbin/faithd/test/faithd.rb
Normal 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
|
Loading…
Reference in New Issue
Block a user