summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2000-07-05 19:34:43 +0000
committerume <ume@FreeBSD.org>2000-07-05 19:34:43 +0000
commitd3c71f0efbb39b37472b918609511858e32a05de (patch)
treeb33ca97e6c4ce735407a4ea6a42248f1d8abdf04
parentade2fdc9b1701bac09b782a5085218e81f59686d (diff)
downloadFreeBSD-src-d3c71f0efbb39b37472b918609511858e32a05de.zip
FreeBSD-src-d3c71f0efbb39b37472b918609511858e32a05de.tar.gz
IPv6 support.
This is required for forthcoming IPv6 ready installer. Obtained from: KAME
-rw-r--r--lib/libftpio/Makefile3
-rw-r--r--lib/libftpio/ftp.errors3
-rw-r--r--lib/libftpio/ftpio.321
-rw-r--r--lib/libftpio/ftpio.c349
-rw-r--r--lib/libftpio/ftpio.h3
5 files changed, 301 insertions, 78 deletions
diff --git a/lib/libftpio/Makefile b/lib/libftpio/Makefile
index 7709dea..b3a749b 100644
--- a/lib/libftpio/Makefile
+++ b/lib/libftpio/Makefile
@@ -1,12 +1,13 @@
# $FreeBSD$
LIB= ftpio
-SHLIB_MAJOR= 5
+SHLIB_MAJOR= 6
SHLIB_MINOR= 0
SRCS= ftpio.c ftperr.c
INCS= ftpio.h
CFLAGS+= -I${.CURDIR} -Wall
+CFLAGS+= -DINET6
MAN3= ftpio.3
CLEANFILES= ftperr.c
diff --git a/lib/libftpio/ftp.errors b/lib/libftpio/ftp.errors
index 7ae4445..c03eeac 100644
--- a/lib/libftpio/ftp.errors
+++ b/lib/libftpio/ftp.errors
@@ -18,7 +18,8 @@
221 Service closing control connection
225 Data connection open; no transfer in progress
226 Requested file action successful
-227 Entering Passive Mode
+227 Entering Passive Mode
+229 Entering Extended Passive Mode
230 User logged in, proceed
250 Requested file action okay, completed
257 File/directory created
diff --git a/lib/libftpio/ftpio.3 b/lib/libftpio/ftpio.3
index b20b8f5..510324d 100644
--- a/lib/libftpio/ftpio.3
+++ b/lib/libftpio/ftpio.3
@@ -39,7 +39,10 @@
.Nm ftpPassive ,
.Nm ftpVerbose ,
.Nm ftpGetURL ,
-.Nm ftpPutURL
+.Nm ftpPutURL ,
+.Nm ftpLoginAf ,
+.Nm ftpGetURLAf ,
+.Nm ftpPutURLAf
.Nd FTPIO User library
.Sh SYNOPSIS
.Fd #include <ftpio.h>
@@ -71,6 +74,12 @@
.Fn ftpGetURL "char *url, char *user, char *passwd, int *retcode"
.Ft FILE *
.Fn ftpPutURL "char *url, char *user, char *passwd, int *retcode"
+.Ft int
+.Fn ftpLoginAf "char *host" "int af" "char *user" "char *passwd" "int ftp_port" "int verbose" "int *retcode"
+.Ft FILE *
+.Fn ftpGetURLAf "char *url" "int af" "char *user" "char *passwd" "int *retcode"
+.Ft FILE *
+.Fn ftpPutURLAf "char *url" "int af" "char *user" "char *passwd" "int *retcode"
.Sh DESCRIPTION
These functions implement a high-level library for managing FTP connections.
@@ -186,6 +195,16 @@ operations except that no server stream is ever returned - the connection
to the server closes when the file has been completely written. Use the
lower-level routines if multiple puts are required as it will be far more
efficient.
+.Pp
+.Fn ftpLoginAf ,
+.Fn ftpGetURLAf ,
+.Fn ftpPutURLAf
+are same as
+.Fn ftpLogin ,
+.Fn ftpGetURL ,
+.Fn ftpPutURL
+except that they are able to specify address family
+.Fa af .
.Sh ENVIRONMENT
.Bl -tag -width FTP_PASSIVE_MODE -offset 123
.It Ev FTP_TIMEOUT
diff --git a/lib/libftpio/ftpio.c b/lib/libftpio/ftpio.c
index ceb428c..0c5c0ef 100644
--- a/lib/libftpio/ftpio.c
+++ b/lib/libftpio/ftpio.c
@@ -58,13 +58,14 @@ static __inline char *get_a_line(FTP_t ftp);
static int get_a_number(FTP_t ftp, char **q);
static int botch(char *func, char *botch_state);
static int cmd(FTP_t ftp, const char *fmt, ...);
-static int ftp_login_session(FTP_t ftp, char *host, char *user, char *passwd, int port, int verbose);
+static int ftp_login_session(FTP_t ftp, char *host, int af, char *user, char *passwd, int port, int verbose);
static int ftp_file_op(FTP_t ftp, char *operation, char *file, FILE **fp, char *mode, off_t *seekto);
static int ftp_close(FTP_t ftp);
static int get_url_info(char *url_in, char *host_ret, int *port_ret, char *name_ret);
static void ftp_timeout(int sig);
static void ftp_set_timeout(void);
static void ftp_clear_timeout(void);
+static void ai_unmapped(struct addrinfo *);
/* Global status variable - ick */
@@ -79,6 +80,8 @@ int FtpTimedOut;
#define FTP_QUIT_HAPPY 221
#define FTP_TRANSFER_HAPPY 226
#define FTP_PASSIVE_HAPPY 227
+#define FTP_LPASSIVE_HAPPY 228
+#define FTP_EPASSIVE_HAPPY 229
#define FTP_CHDIR_HAPPY 250
/* FTP unhappy status codes */
@@ -267,6 +270,16 @@ ftpGet(FILE *fp, char *file, off_t *seekto)
FILE *
ftpLogin(char *host, char *user, char *passwd, int port, int verbose, int *retcode)
{
+#ifdef INET6
+ return ftpLoginAf(host, AF_UNSPEC, user, passwd, port, verbose, retcode);
+#else
+ return ftpLoginAf(host, AF_INET, user, passwd, port, verbose, retcode);
+#endif
+}
+
+FILE *
+ftpLoginAf(char *host, int af, char *user, char *passwd, int port, int verbose, int *retcode)
+{
FTP_t n;
FILE *fp;
@@ -277,7 +290,7 @@ ftpLogin(char *host, char *user, char *passwd, int port, int verbose, int *retco
n = ftp_new();
fp = NULL;
- if (n && ftp_login_session(n, host, user, passwd, port, verbose) == SUCCESS) {
+ if (n && ftp_login_session(n, host, af, user, passwd, port, verbose) == SUCCESS) {
fp = funopen(n, ftp_read_method, ftp_write_method, NULL, ftp_close_method); /* BSD 4.4 function! */
fp->_file = n->fd_ctrl;
}
@@ -323,11 +336,27 @@ ftpPassive(FILE *fp, int st)
if (ftp->is_passive == st)
return SUCCESS;
- i = cmd(ftp, "PASV");
- if (i < 0)
- return i;
- if (i != FTP_PASSIVE_HAPPY)
- return FAILURE;
+ switch (ftp->addrtype) {
+ case AF_INET:
+ i = cmd(ftp, "PASV");
+ if (i < 0)
+ return i;
+ if (i != FTP_PASSIVE_HAPPY)
+ return FAILURE;
+ break;
+ case AF_INET6:
+ i = cmd(ftp, "EPSV");
+ if (i < 0)
+ return i;
+ if (i != FTP_EPASSIVE_HAPPY) {
+ i = cmd(ftp, "LPSV");
+ if (i < 0)
+ return i;
+ if (i != FTP_LPASSIVE_HAPPY)
+ return FAILURE;
+ }
+ break;
+ }
ftp->is_passive = !ftp->is_passive;
return SUCCESS;
}
@@ -335,6 +364,16 @@ ftpPassive(FILE *fp, int st)
FILE *
ftpGetURL(char *url, char *user, char *passwd, int *retcode)
{
+#ifdef INET6
+ return ftpGetURLAf(url, AF_UNSPEC, user, passwd, retcode);
+#else
+ return ftpGetURLAf(url, AF_INET, user, passwd, retcode);
+#endif
+}
+
+FILE *
+ftpGetURLAf(char *url, int af, char *user, char *passwd, int *retcode)
+{
char host[255], name[255];
int port;
FILE *fp2;
@@ -364,7 +403,7 @@ ftpGetURL(char *url, char *user, char *passwd, int *retcode)
prev_host = NULL;
}
}
- fp = ftpLogin(host, user, passwd, port, 0, retcode);
+ fp = ftpLoginAf(host, af, user, passwd, port, 0, retcode);
if (fp) {
fp2 = ftpGet(fp, name, NULL);
if (!fp2) {
@@ -385,6 +424,17 @@ ftpGetURL(char *url, char *user, char *passwd, int *retcode)
FILE *
ftpPutURL(char *url, char *user, char *passwd, int *retcode)
{
+#ifdef INET6
+ return ftpPutURLAf(url, AF_UNSPEC, user, passwd, retcode);
+#else
+ return ftpPutURLAf(url, AF_INET, user, passwd, retcode);
+#endif
+
+}
+
+FILE *
+ftpPutURLAf(char *url, int af, char *user, char *passwd, int *retcode)
+{
char host[255], name[255];
int port;
static FILE *fp = NULL;
@@ -397,7 +447,7 @@ ftpPutURL(char *url, char *user, char *passwd, int *retcode)
fp = NULL;
}
if (get_url_info(url, host, &port, name) == SUCCESS) {
- fp = ftpLogin(host, user, passwd, port, 0, retcode);
+ fp = ftpLoginAf(host, af, user, passwd, port, 0, retcode);
if (fp) {
fp2 = ftpPut(fp, name);
if (!fp2) {
@@ -672,12 +722,13 @@ cmd(FTP_t ftp, const char *fmt, ...)
}
static int
-ftp_login_session(FTP_t ftp, char *host, char *user, char *passwd, int port, int verbose)
+ftp_login_session(FTP_t ftp, char *host, int af,
+ char *user, char *passwd, int port, int verbose)
{
- struct hostent *he = NULL;
- struct sockaddr_in sin;
+ char pbuf[10];
+ struct addrinfo hints, *res, *res0;
+ int err;
int s;
- unsigned long temp;
int i;
if (networkInit() != SUCCESS)
@@ -698,30 +749,36 @@ ftp_login_session(FTP_t ftp, char *host, char *user, char *passwd, int port, int
if (!port)
port = 21;
- temp = inet_addr(host);
- if (temp != INADDR_NONE) {
- ftp->addrtype = sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = temp;
- }
- else {
- he = gethostbyname(host);
- if (!he) {
- ftp->error = 0;
- return FAILURE;
- }
- ftp->addrtype = sin.sin_family = he->h_addrtype;
- bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length);
+ snprintf(pbuf, sizeof(pbuf), "%d", port);
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ err = getaddrinfo(host, pbuf, &hints, &res0);
+ if (err) {
+ ftp->error = 0;
+ return FAILURE;
}
- sin.sin_port = htons(port);
+ s = -1;
+ for (res = res0; res; res = res->ai_next) {
+ ai_unmapped(res);
+ ftp->addrtype = res->ai_family;
- if ((s = socket(ftp->addrtype, SOCK_STREAM, 0)) < 0) {
- ftp->error = -1;
- return FAILURE;
- }
+ if ((s = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol)) < 0)
+ continue;
+
+ if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
+ (void)close(s);
+ s = -1;
+ continue;
+ }
- if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
- (void)close(s);
+ break;
+ }
+ freeaddrinfo(res0);
+ if (s < 0) {
ftp->error = errno;
return FAILURE;
}
@@ -745,11 +802,14 @@ ftp_login_session(FTP_t ftp, char *host, char *user, char *passwd, int port, int
static int
ftp_file_op(FTP_t ftp, char *operation, char *file, FILE **fp, char *mode, off_t *seekto)
{
- int i,s;
+ int i,l,s;
char *q;
unsigned char addr[64];
- struct sockaddr_in sin;
- u_long a;
+ union sockaddr_cmn {
+ struct sockaddr_in sin4;
+ struct sockaddr_in6 sin6;
+ } sin;
+ char *cmdstr;
if (!fp)
return FAILURE;
@@ -764,35 +824,101 @@ ftp_file_op(FTP_t ftp, char *operation, char *file, FILE **fp, char *mode, off_t
}
if (ftp->is_passive) {
- if (ftp->is_verbose)
- fprintf(stderr, "Sending PASV\n");
- if (writes(ftp->fd_ctrl, "PASV\r\n")) {
- ftp_close(ftp);
- if (FtpTimedOut)
- ftp->error = FTP_TIMED_OUT;
- return FTP_TIMED_OUT;
- }
- i = get_a_number(ftp, &q);
- if (check_code(ftp, i, FTP_PASSIVE_HAPPY)) {
- ftp_close(ftp);
- return i;
+ if (ftp->addrtype == AF_INET) {
+ if (ftp->is_verbose)
+ fprintf(stderr, "Sending PASV\n");
+ if (writes(ftp->fd_ctrl, "PASV\r\n")) {
+ ftp_close(ftp);
+ if (FtpTimedOut)
+ ftp->error = FTP_TIMED_OUT;
+ return FTP_TIMED_OUT;
+ }
+ i = get_a_number(ftp, &q);
+ if (check_code(ftp, i, FTP_PASSIVE_HAPPY)) {
+ ftp_close(ftp);
+ return i;
+ }
+ cmdstr = "PASV";
+ } else {
+ if (ftp->is_verbose)
+ fprintf(stderr, "Sending EPSV\n");
+ if (writes(ftp->fd_ctrl, "EPSV\r\n")) {
+ ftp_close(ftp);
+ if (FtpTimedOut)
+ ftp->error = FTP_TIMED_OUT;
+ return FTP_TIMED_OUT;
+ }
+ i = get_a_number(ftp, &q);
+ if (check_code(ftp, i, FTP_EPASSIVE_HAPPY)) {
+ if (ftp->is_verbose)
+ fprintf(stderr, "Sending LPSV\n");
+ if (writes(ftp->fd_ctrl, "LPSV\r\n")) {
+ ftp_close(ftp);
+ if (FtpTimedOut)
+ ftp->error = FTP_TIMED_OUT;
+ return FTP_TIMED_OUT;
+ }
+ i = get_a_number(ftp, &q);
+ if (check_code(ftp, i, FTP_LPASSIVE_HAPPY)) {
+ ftp_close(ftp);
+ return i;
+ }
+ cmdstr = "LPSV";
+ } else
+ cmdstr = "EPSV";
}
- while (*q && !isdigit(*q))
+ while (*q && *q != '(') /* ) */
q++;
if (!*q) {
ftp_close(ftp);
return FAILURE;
}
- q--;
- for (i = 0; i < 6; i++) {
+ if (strcmp(cmdstr, "PASV") == 0 || strcmp(cmdstr, "LPSV") == 0) {
+ l = (ftp->addrtype == AF_INET ? 6 : 21);
+ for (i = 0; i < l; i++) {
+ q++;
+ addr[i] = strtol(q, &q, 10);
+ }
+
+ sin.sin4.sin_family = ftp->addrtype;
+ if (ftp->addrtype == AF_INET6) {
+ sin.sin6.sin6_len = sizeof(struct sockaddr_in6);
+ bcopy(addr + 2, (char *)&sin.sin6.sin6_addr, 16);
+ bcopy(addr + 19, (char *)&sin.sin6.sin6_port, 2);
+ } else {
+ sin.sin4.sin_len = sizeof(struct sockaddr_in);
+ bcopy(addr, (char *)&sin.sin4.sin_addr, 4);
+ bcopy(addr + 4, (char *)&sin.sin4.sin_port, 2);
+ }
+ } else if (strcmp(cmdstr, "EPSV") == 0) {
+ int port;
+ int sinlen;
q++;
- addr[i] = strtol(q, &q, 10);
+ if (sscanf(q, "%c%c%c%d%c", &addr[0], &addr[1], &addr[2],
+ &port, &addr[3]) != 5
+ || addr[0] != addr[1] || addr[0] != addr[2] || addr[0] != addr[3]) {
+ ftp_close(ftp);
+ return FAILURE;
+ }
+ sinlen = sizeof(sin);
+ if (getpeername(ftp->fd_ctrl, (struct sockaddr *)&sin, &sinlen) < 0) {
+ ftp_close(ftp);
+ return FAILURE;
+ }
+ switch (sin.sin4.sin_family) {
+ case AF_INET:
+ sin.sin4.sin_port = htons(port);
+ break;
+ case AF_INET6:
+ sin.sin6.sin6_port = htons(port);
+ break;
+ default:
+ ftp_close(ftp);
+ return FAILURE;
+ }
}
- sin.sin_family = ftp->addrtype;
- bcopy(addr, (char *)&sin.sin_addr, 4);
- bcopy(addr + 4, (char *)&sin.sin_port, 2);
- if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ if (connect(s, (struct sockaddr *)&sin, sin.sin4.sin_len) < 0) {
(void)close(s);
return FAILURE;
}
@@ -817,39 +943,85 @@ ftp_file_op(FTP_t ftp, char *operation, char *file, FILE **fp, char *mode, off_t
else {
int fd,portrange;
+#ifdef IPV6_PORTRANGE
+ if (ftp->addrtype == AF_INET6) {
+ portrange = IPV6_PORTRANGE_HIGH;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_PORTRANGE, (char *)
+ &portrange, sizeof(portrange)) < 0) {
+ close(s);
+ return FAILURE;
+ }
+ }
+#endif
#ifdef IP_PORTRANGE
- portrange = IP_PORTRANGE_HIGH;
- if (setsockopt(s, IPPROTO_IP, IP_PORTRANGE, (char *)
- &portrange, sizeof(portrange)) < 0) {
- close(s);
- return FAILURE;
- };
+ if (ftp->addrtype == AF_INET) {
+ portrange = IP_PORTRANGE_HIGH;
+ if (setsockopt(s, IPPROTO_IP, IP_PORTRANGE, (char *)
+ &portrange, sizeof(portrange)) < 0) {
+ close(s);
+ return FAILURE;
+ }
+ }
#endif
i = sizeof sin;
getsockname(ftp->fd_ctrl, (struct sockaddr *)&sin, &i);
- sin.sin_port = 0;
- i = sizeof sin;
+ sin.sin4.sin_port = 0;
+ i = ((struct sockaddr *)&sin)->sa_len;
if (bind(s, (struct sockaddr *)&sin, i) < 0) {
close(s);
return FAILURE;
}
+ i = sizeof sin;
getsockname(s,(struct sockaddr *)&sin,&i);
if (listen(s, 1) < 0) {
close(s);
return FAILURE;
}
- a = ntohl(sin.sin_addr.s_addr);
- i = cmd(ftp, "PORT %d,%d,%d,%d,%d,%d",
- (a >> 24) & 0xff,
- (a >> 16) & 0xff,
- (a >> 8) & 0xff,
- a & 0xff,
- (ntohs(sin.sin_port) >> 8) & 0xff,
- ntohs(sin.sin_port) & 0xff);
- if (check_code(ftp, i, FTP_PORT_HAPPY)) {
- close(s);
- return i;
+ if (sin.sin4.sin_family == AF_INET) {
+ u_long a;
+ a = ntohl(sin.sin4.sin_addr.s_addr);
+ i = cmd(ftp, "PORT %d,%d,%d,%d,%d,%d",
+ (a >> 24) & 0xff,
+ (a >> 16) & 0xff,
+ (a >> 8) & 0xff,
+ a & 0xff,
+ (ntohs(sin.sin4.sin_port) >> 8) & 0xff,
+ ntohs(sin.sin4.sin_port) & 0xff);
+ if (check_code(ftp, i, FTP_PORT_HAPPY)) {
+ close(s);
+ return i;
+ }
+ } else {
+#define UC(b) (((int)b)&0xff)
+ char *a;
+ char hname[INET6_ADDRSTRLEN];
+
+ if (getnameinfo((struct sockaddr *)&sin, sin.sin6.sin6_len,
+ hname, sizeof(hname),
+ NULL, 0, NI_NUMERICHOST) != 0) {
+ goto try_lprt;
+ }
+ i = cmd(ftp, "EPRT |%d|%s|%d|", 2, hname,
+ htons(sin.sin6.sin6_port));
+ if (check_code(ftp, i, FTP_PORT_HAPPY)) {
+try_lprt:
+ a = (char *)&sin.sin6.sin6_addr;
+ i = cmd(ftp,
+"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,
+ (ntohs(sin.sin4.sin_port) >> 8) & 0xff,
+ ntohs(sin.sin4.sin_port) & 0xff);
+ if (check_code(ftp, i, FTP_PORT_HAPPY)) {
+ close(s);
+ return i;
+ }
+ }
}
if (seekto && *seekto) {
i = cmd(ftp, "REST %d", *seekto);
@@ -881,3 +1053,30 @@ ftp_file_op(FTP_t ftp, char *operation, char *file, FILE **fp, char *mode, off_t
else
return FAILURE;
}
+
+static void
+ai_unmapped(struct addrinfo *ai)
+{
+ struct sockaddr_in6 *sin6;
+ struct sockaddr_in sin;
+
+ if (ai->ai_family != AF_INET6)
+ return;
+ if (ai->ai_addrlen != sizeof(struct sockaddr_in6) ||
+ sizeof(sin) > ai->ai_addrlen)
+ return;
+ sin6 = (struct sockaddr_in6 *)ai->ai_addr;
+ if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
+ return;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(struct sockaddr_in);
+ memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12],
+ sizeof(sin.sin_addr));
+ sin.sin_port = sin6->sin6_port;
+
+ ai->ai_family = AF_INET;
+ memcpy(ai->ai_addr, &sin, sin.sin_len);
+ ai->ai_addrlen = sin.sin_len;
+}
diff --git a/lib/libftpio/ftpio.h b/lib/libftpio/ftpio.h
index 26d4f90..ed6fd82 100644
--- a/lib/libftpio/ftpio.h
+++ b/lib/libftpio/ftpio.h
@@ -63,6 +63,9 @@ extern FILE *ftpGetURL(char *url, char *user, char *passwd, int *retcode);
extern FILE *ftpPutURL(char *url, char *user, char *passwd, int *retcode);
extern time_t ftpGetModtime(FILE *fp, char *s);
extern const char *ftpErrString(int error);
+extern FILE *ftpLoginAf(char *host, int af, char *user, char *passwd, int port, int verbose, int *retcode);
+extern FILE *ftpGetURLAf(char *url, int af, char *user, char *passwd, int *retcode);
+extern FILE *ftpPutURLAf(char *url, int af, char *user, char *passwd, int *retcode);
__END_DECLS
#endif /* _FTP_H_INCLUDE */
OpenPOWER on IntegriCloud