diff options
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/ftp/Makefile | 1 | ||||
-rw-r--r-- | usr.bin/ftp/extern.h | 2 | ||||
-rw-r--r-- | usr.bin/ftp/fetch.c | 107 | ||||
-rw-r--r-- | usr.bin/ftp/ftp.1 | 22 | ||||
-rw-r--r-- | usr.bin/ftp/ftp.c | 416 | ||||
-rw-r--r-- | usr.bin/ftp/ftp_var.h | 11 | ||||
-rw-r--r-- | usr.bin/ftp/main.c | 69 | ||||
-rw-r--r-- | usr.bin/ftp/util.c | 17 | ||||
-rw-r--r-- | usr.bin/telnet/Makefile | 6 | ||||
-rw-r--r-- | usr.bin/telnet/commands.c | 428 | ||||
-rw-r--r-- | usr.bin/telnet/externs.h | 10 | ||||
-rw-r--r-- | usr.bin/telnet/main.c | 46 | ||||
-rw-r--r-- | usr.bin/telnet/telnet.1 | 11 |
13 files changed, 802 insertions, 344 deletions
diff --git a/usr.bin/ftp/Makefile b/usr.bin/ftp/Makefile index bbd82e2..b5a59cc 100644 --- a/usr.bin/ftp/Makefile +++ b/usr.bin/ftp/Makefile @@ -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} diff --git a/usr.bin/ftp/extern.h b/usr.bin/ftp/extern.h index a8ac97b..7841f7b 100644 --- a/usr.bin/ftp/extern.h +++ b/usr.bin/ftp/extern.h @@ -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)); diff --git a/usr.bin/ftp/fetch.c b/usr.bin/ftp/fetch.c index 1d73c0f..62b64e9 100644 --- a/usr.bin/ftp/fetch.c +++ b/usr.bin/ftp/fetch.c @@ -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 @@ parsed_url: 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; +} diff --git a/usr.bin/ftp/ftp.1 b/usr.bin/ftp/ftp.1 index 59b371f..a112709 100644 --- a/usr.bin/ftp/ftp.1 +++ b/usr.bin/ftp/ftp.1 @@ -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. diff --git a/usr.bin/ftp/ftp.c b/usr.bin/ftp/ftp.c index d2edd01..3c7da3f 100644 --- a/usr.bin/ftp/ftp.c +++ b/usr.bin/ftp/ftp.c @@ -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; + 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)); - } 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)); + 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 @@ noport: 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 +#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, sizeof(data_addr)) < 0) { + if (bind(data, (struct sockaddr *)&data_addr, data_addr.su_len) < 0) { warn("bind"); goto bad; } @@ -1184,13 +1378,79 @@ noport: 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 @@ noport: 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; diff --git a/usr.bin/ftp/ftp_var.h b/usr.bin/ftp/ftp_var.h index d26d22d..cd9b0bd 100644 --- a/usr.bin/ftp/ftp_var.h +++ b/usr.bin/ftp/ftp_var.h @@ -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 */ diff --git a/usr.bin/ftp/main.c b/usr.bin/ftp/main.c index 3717308..aeb7487 100644 --- a/usr.bin/ftp/main.c +++ b/usr.bin/ftp/main.c @@ -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 */ diff --git a/usr.bin/ftp/util.c b/usr.bin/ftp/util.c index a34ca34..a62565c 100644 --- a/usr.bin/ftp/util.c +++ b/usr.bin/ftp/util.c @@ -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') diff --git a/usr.bin/telnet/Makefile b/usr.bin/telnet/Makefile index 658a2b7..b4faf30 100644 --- a/usr.bin/telnet/Makefile +++ b/usr.bin/telnet/Makefile @@ -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 diff --git a/usr.bin/telnet/commands.c b/usr.bin/telnet/commands.c index a4677e0..a640bec 100644 --- a/usr.bin/telnet/commands.c +++ b/usr.bin/telnet/commands.c @@ -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); + 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; - } - 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)); } + 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++; + 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; + } + 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; - temp = sourceroute(hostp, &srp, &srlen); - if (temp == 0) { - herror(srp); + result = sourceroute(res, hostp, &srp, &srlen, &proto, &opt); + if (result == 0) { setuid(getuid()); + freeaddrinfo(res); return 0; - } else if (temp == -1) { + } 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 diff --git a/usr.bin/telnet/externs.h b/usr.bin/telnet/externs.h index a8c3f24..10e89ac 100644 --- a/usr.bin/telnet/externs.h +++ b/usr.bin/telnet/externs.h @@ -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 */ diff --git a/usr.bin/telnet/main.c b/usr.bin/telnet/main.c index 298389c..9126738 100644 --- a/usr.bin/telnet/main.c +++ b/usr.bin/telnet/main.c @@ -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) @@ -98,6 +108,9 @@ usage() #else "[-r] [-s src_addr] ", #endif +#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) + "[-P policy]" +#endif "[host-name [port]]" ); exit(1); @@ -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(); diff --git a/usr.bin/telnet/telnet.1 b/usr.bin/telnet/telnet.1 index ca2e968..dfa4fcf 100644 --- a/usr.bin/telnet/telnet.1 +++ b/usr.bin/telnet/telnet.1 @@ -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 |