389 lines
11 KiB
Diff
389 lines
11 KiB
Diff
|
--- mc-2006-09-12-21/vfs/ftpfs.c.ipv6 2006-03-08 16:17:55.000000000 +0100
|
||
|
+++ mc-2006-09-12-21/vfs/ftpfs.c 2006-09-26 10:43:27.000000000 +0200
|
||
|
@@ -639,12 +639,13 @@ ftpfs_get_proxy_host_and_port (const cha
|
||
|
static int
|
||
|
ftpfs_open_socket (struct vfs_class *me, struct vfs_s_super *super)
|
||
|
{
|
||
|
- struct sockaddr_in server_address;
|
||
|
- struct hostent *hp;
|
||
|
- int my_socket;
|
||
|
+ struct addrinfo hints, *res, *restmp;
|
||
|
+ int my_socket = 0;
|
||
|
char *host;
|
||
|
- int port = SUP.port;
|
||
|
+ char *port;
|
||
|
+ int tmp_port;
|
||
|
int free_host = 0;
|
||
|
+ int e;
|
||
|
|
||
|
(void) me;
|
||
|
|
||
|
@@ -657,62 +658,83 @@ ftpfs_open_socket (struct vfs_class *me,
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
+ port = malloc (sizeof (char) * 6);
|
||
|
+ if (port == NULL) {
|
||
|
+ ftpfs_errno = errno;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
/* Hosts to connect to that start with a ! should use proxy */
|
||
|
+ tmp_port = SUP.port;
|
||
|
+
|
||
|
if (SUP.proxy){
|
||
|
- ftpfs_get_proxy_host_and_port (ftpfs_proxy_host, &host, &port);
|
||
|
+ ftpfs_get_proxy_host_and_port (ftpfs_proxy_host, &host, &tmp_port);
|
||
|
free_host = 1;
|
||
|
}
|
||
|
|
||
|
- enable_interrupt_key(); /* clear the interrupt flag */
|
||
|
-
|
||
|
- /* Get host address */
|
||
|
- memset ((char *) &server_address, 0, sizeof (server_address));
|
||
|
- server_address.sin_family = AF_INET;
|
||
|
- server_address.sin_addr.s_addr = inet_addr (host);
|
||
|
- if (server_address.sin_addr.s_addr == INADDR_NONE) {
|
||
|
- hp = gethostbyname (host);
|
||
|
- if (hp == NULL){
|
||
|
- disable_interrupt_key();
|
||
|
- print_vfs_message (_("ftpfs: Invalid host address."));
|
||
|
- ftpfs_errno = EINVAL;
|
||
|
- if (free_host)
|
||
|
- g_free (host);
|
||
|
- return -1;
|
||
|
- }
|
||
|
- server_address.sin_family = hp->h_addrtype;
|
||
|
-
|
||
|
- /* We copy only 4 bytes, we cannot trust hp->h_length, as it comes from the DNS */
|
||
|
- memcpy ((char *) &server_address.sin_addr, (char *) hp->h_addr, 4);
|
||
|
+ if (snprintf (port, 6, "%hu", (unsigned short)tmp_port) < 0) {
|
||
|
+ g_free (port);
|
||
|
+ if (free_host)
|
||
|
+ g_free (host);
|
||
|
+ ftpfs_errno = errno;
|
||
|
+ return -1;
|
||
|
}
|
||
|
|
||
|
- server_address.sin_port = htons (port);
|
||
|
+ enable_interrupt_key(); /* clear the interrupt flag */
|
||
|
|
||
|
- /* Connect */
|
||
|
- if ((my_socket = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
|
||
|
- disable_interrupt_key();
|
||
|
- ftpfs_errno = errno;
|
||
|
- if (free_host)
|
||
|
- g_free (host);
|
||
|
- return -1;
|
||
|
- }
|
||
|
-
|
||
|
- print_vfs_message (_("ftpfs: making connection to %s"), host);
|
||
|
- if (free_host)
|
||
|
+ memset (&hints, 0, sizeof (struct addrinfo));
|
||
|
+ hints.ai_socktype = SOCK_STREAM;
|
||
|
+ hints.ai_flags = AI_ADDRCONFIG;
|
||
|
+
|
||
|
+ if ((e = getaddrinfo (host, port, &hints, &res)) != 0) {
|
||
|
+ disable_interrupt_key();
|
||
|
+ print_vfs_message (_("ftpfs: %s"), gai_strerror (e));
|
||
|
+ if (free_host)
|
||
|
g_free (host);
|
||
|
-
|
||
|
- if (connect (my_socket, (struct sockaddr *) &server_address,
|
||
|
- sizeof (server_address)) < 0){
|
||
|
- ftpfs_errno = errno;
|
||
|
- if (errno == EINTR && got_interrupt ())
|
||
|
+ g_free (port);
|
||
|
+ ftpfs_errno = EINVAL;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ g_free (port);
|
||
|
+
|
||
|
+ for (restmp = res; res != NULL; res = res->ai_next) {
|
||
|
+ my_socket = socket (res->ai_family, res->ai_socktype, res->ai_protocol);
|
||
|
+ if (my_socket < 0) {
|
||
|
+ if (res->ai_next == NULL) {
|
||
|
+ disable_interrupt_key();
|
||
|
+ print_vfs_message (_("ftpfs: %s"), unix_error_string (errno));
|
||
|
+ if (free_host)
|
||
|
+ g_free (host);
|
||
|
+ freeaddrinfo (restmp);
|
||
|
+ ftpfs_errno = errno;
|
||
|
+ return -1;
|
||
|
+ } else
|
||
|
+ continue;
|
||
|
+ } else {
|
||
|
+ print_vfs_message (_("ftpfs: making connection to %s"), host);
|
||
|
+ if (free_host)
|
||
|
+ g_free (host);
|
||
|
+
|
||
|
+ if (connect (my_socket, res->ai_addr, res->ai_addrlen) < 0) {
|
||
|
+ ftpfs_errno = errno;
|
||
|
+ close (my_socket);
|
||
|
+ if (errno == EINTR && got_interrupt ()) {
|
||
|
print_vfs_message (_("ftpfs: connection interrupted by user"));
|
||
|
- else
|
||
|
+ } else if (res->ai_next == NULL) {
|
||
|
print_vfs_message (_("ftpfs: connection to server failed: %s"),
|
||
|
- unix_error_string(errno));
|
||
|
- disable_interrupt_key();
|
||
|
- close (my_socket);
|
||
|
- return -1;
|
||
|
+ unix_error_string (errno));
|
||
|
+ } else
|
||
|
+ continue;
|
||
|
+ freeaddrinfo (restmp);
|
||
|
+ disable_interrupt_key ();
|
||
|
+ return -1;
|
||
|
+ } else
|
||
|
+ break;
|
||
|
+ }
|
||
|
}
|
||
|
- disable_interrupt_key();
|
||
|
+
|
||
|
+ freeaddrinfo (restmp);
|
||
|
+ disable_interrupt_key ();
|
||
|
return my_socket;
|
||
|
}
|
||
|
|
||
|
@@ -861,93 +883,179 @@ ftpfs_get_current_directory (struct vfs_
|
||
|
|
||
|
/* Setup Passive ftp connection, we use it for source routed connections */
|
||
|
static int
|
||
|
-ftpfs_setup_passive (struct vfs_class *me, struct vfs_s_super *super, int my_socket, struct sockaddr_in *sa)
|
||
|
+ftpfs_setup_passive (struct vfs_class *me, struct vfs_s_super *super, int my_socket, struct sockaddr_storage *sa, socklen_t *salen)
|
||
|
{
|
||
|
+ char *c;
|
||
|
+
|
||
|
+ if (ftpfs_command (me, super, WAIT_REPLY | WANT_STRING, "EPSV") == COMPLETE) {
|
||
|
+ int port;
|
||
|
+ /* (|||<port>|) */
|
||
|
+ c = strchr (reply_str, '|');
|
||
|
+ if (c == NULL)
|
||
|
+ return 0;
|
||
|
+ if(strlen(c) > 3)
|
||
|
+ c+=3;
|
||
|
+ else
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ port = atoi (c);
|
||
|
+ if (port < 0 || port > 65535)
|
||
|
+ return 0;
|
||
|
+ port = htons (port);
|
||
|
+
|
||
|
+ switch (sa->ss_family) {
|
||
|
+ case AF_INET:
|
||
|
+ ((struct sockaddr_in *)sa)->sin_port = port;
|
||
|
+ break;
|
||
|
+ case AF_INET6:
|
||
|
+ ((struct sockaddr_in6 *)sa)->sin6_port = port;
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ print_vfs_message (_("ftpfs: invalid address family"));
|
||
|
+ ERRNOR (EINVAL, -1);
|
||
|
+ }
|
||
|
+ } else if (sa->ss_family == AF_INET) {
|
||
|
int xa, xb, xc, xd, xe, xf;
|
||
|
char n [6];
|
||
|
- char *c;
|
||
|
|
||
|
if (ftpfs_command (me, super, WAIT_REPLY | WANT_STRING, "PASV") != COMPLETE)
|
||
|
- return 0;
|
||
|
-
|
||
|
+ return 0;
|
||
|
+
|
||
|
/* Parse remote parameters */
|
||
|
for (c = reply_str + 4; (*c) && (!isdigit ((unsigned char) *c)); c++)
|
||
|
- ;
|
||
|
+ ;
|
||
|
if (!*c)
|
||
|
- return 0;
|
||
|
+ return 0;
|
||
|
if (!isdigit ((unsigned char) *c))
|
||
|
- return 0;
|
||
|
+ return 0;
|
||
|
if (sscanf (c, "%d,%d,%d,%d,%d,%d", &xa, &xb, &xc, &xd, &xe, &xf) != 6)
|
||
|
- return 0;
|
||
|
+ return 0;
|
||
|
n [0] = (unsigned char) xa;
|
||
|
n [1] = (unsigned char) xb;
|
||
|
n [2] = (unsigned char) xc;
|
||
|
n [3] = (unsigned char) xd;
|
||
|
n [4] = (unsigned char) xe;
|
||
|
n [5] = (unsigned char) xf;
|
||
|
+
|
||
|
+ memcpy (&(((struct sockaddr_in *)sa)->sin_addr.s_addr), (void *)n, 4);
|
||
|
+ memcpy (&(((struct sockaddr_in *)sa)->sin_port), (void *)&n[4], 2);
|
||
|
+ } else
|
||
|
+ return 0;
|
||
|
|
||
|
- memcpy (&(sa->sin_addr.s_addr), (void *)n, 4);
|
||
|
- memcpy (&(sa->sin_port), (void *)&n[4], 2);
|
||
|
- if (connect (my_socket, (struct sockaddr *) sa, sizeof (struct sockaddr_in)) < 0)
|
||
|
- return 0;
|
||
|
- return 1;
|
||
|
+ if (connect (my_socket, (struct sockaddr *) sa, *salen ) < 0)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ return 1;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
ftpfs_initconn (struct vfs_class *me, struct vfs_s_super *super)
|
||
|
{
|
||
|
- struct sockaddr_in data_addr;
|
||
|
- int data;
|
||
|
- socklen_t len = sizeof(data_addr);
|
||
|
- struct protoent *pe;
|
||
|
+ struct sockaddr_storage data_addr;
|
||
|
+ socklen_t data_addrlen;
|
||
|
+ int data_sock;
|
||
|
|
||
|
- pe = getprotobyname ("tcp");
|
||
|
- if (pe == NULL)
|
||
|
- ERRNOR (EIO, -1);
|
||
|
again:
|
||
|
- if (getsockname (SUP.sock, (struct sockaddr *) &data_addr, &len) == -1)
|
||
|
- ERRNOR (EIO, -1);
|
||
|
- data_addr.sin_port = 0;
|
||
|
-
|
||
|
- data = socket (AF_INET, SOCK_STREAM, pe->p_proto);
|
||
|
- if (data < 0)
|
||
|
- ERRNOR (EIO, -1);
|
||
|
+ memset (&data_addr, 0, sizeof (struct sockaddr_storage));
|
||
|
+ data_addrlen = sizeof (struct sockaddr_storage);
|
||
|
|
||
|
- if (SUP.use_passive_connection) {
|
||
|
- if (ftpfs_setup_passive (me, super, data, &data_addr))
|
||
|
- return data;
|
||
|
-
|
||
|
- SUP.use_passive_connection = 0;
|
||
|
- print_vfs_message (_("ftpfs: could not setup passive mode"));
|
||
|
+ if (getsockname (SUP.sock, (struct sockaddr *) &data_addr, &data_addrlen) == -1)
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ switch (data_addr.ss_family) {
|
||
|
+ case AF_INET:
|
||
|
+ ((struct sockaddr_in *)&data_addr)->sin_port = 0;
|
||
|
+ break;
|
||
|
+ case AF_INET6:
|
||
|
+ ((struct sockaddr_in6 *)&data_addr)->sin6_port = 0;
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ print_vfs_message (_("ftpfs: invalid address family"));
|
||
|
+ ERRNOR(EINVAL, -1);
|
||
|
+ }
|
||
|
|
||
|
- /* data or data_addr may be damaged by ftpfs_setup_passive */
|
||
|
- close (data);
|
||
|
- goto again;
|
||
|
+ data_sock = socket (data_addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
|
||
|
+ if (data_sock < 0) {
|
||
|
+ if (SUP.use_passive_connection) {
|
||
|
+ print_vfs_message (_("ftpfs: could not setup passive mode: %s"), unix_error_string (errno));
|
||
|
+ SUP.use_passive_connection = 0;
|
||
|
+ goto again;
|
||
|
}
|
||
|
+ print_vfs_message (_("ftpfs: could not create socket: %s"), unix_error_string (errno));
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
|
||
|
+ if (SUP.use_passive_connection) {
|
||
|
+ if (ftpfs_setup_passive (me, super, data_sock, &data_addr, &data_addrlen))
|
||
|
+ return data_sock;
|
||
|
+
|
||
|
+ SUP.use_passive_connection = 0;
|
||
|
+ print_vfs_message (_("ftpfs: could not setup passive mode"));
|
||
|
+
|
||
|
+ close (data_sock);
|
||
|
+ goto again;
|
||
|
+ }
|
||
|
+
|
||
|
/* If passive setup fails, fallback to active connections */
|
||
|
/* Active FTP connection */
|
||
|
- if ((bind (data, (struct sockaddr *)&data_addr, len) == 0) &&
|
||
|
- (getsockname (data, (struct sockaddr *) &data_addr, &len) == 0) &&
|
||
|
- (listen (data, 1) == 0))
|
||
|
+ if ((bind (data_sock, (struct sockaddr *)&data_addr, data_addrlen) == 0) &&
|
||
|
+ (getsockname (data_sock, (struct sockaddr *)&data_addr, &data_addrlen) == 0) &&
|
||
|
+ (listen (data_sock, 1) == 0))
|
||
|
{
|
||
|
- unsigned char *a = (unsigned char *)&data_addr.sin_addr;
|
||
|
- unsigned char *p = (unsigned char *)&data_addr.sin_port;
|
||
|
+ unsigned short int port;
|
||
|
+ char *addr;
|
||
|
+ unsigned int af;
|
||
|
+
|
||
|
+ switch (data_addr.ss_family) {
|
||
|
+ case AF_INET:
|
||
|
+ af = FTP_INET;
|
||
|
+ port = ((struct sockaddr_in *)&data_addr)->sin_port;
|
||
|
+ break;
|
||
|
+ case AF_INET6:
|
||
|
+ af = FTP_INET6;
|
||
|
+ port = ((struct sockaddr_in6 *)&data_addr)->sin6_port;
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ print_vfs_message (_("ftpfs: invalid address family"));
|
||
|
+ ERRNOR (EINVAL, -1);
|
||
|
+ }
|
||
|
+ port = ntohs (port);
|
||
|
+
|
||
|
+ addr = malloc (NI_MAXHOST);
|
||
|
+ if (addr == NULL)
|
||
|
+ ERRNOR (ENOMEM, -1);
|
||
|
+
|
||
|
+ if (getnameinfo ((struct sockaddr *)&data_addr, data_addrlen, addr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) {
|
||
|
+ g_free (addr);
|
||
|
+ ERRNOR (EIO, -1);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (ftpfs_command (me, super, WAIT_REPLY, "EPRT |%u|%s|%hu|", af, addr, port) == COMPLETE) {
|
||
|
+ g_free (addr);
|
||
|
+ return data_sock;
|
||
|
+ }
|
||
|
+ g_free (addr);
|
||
|
+
|
||
|
+ if (FTP_INET == af) {
|
||
|
+ unsigned char *a = (unsigned char *)&((struct sockaddr_in *)&data_addr)->sin_addr;
|
||
|
+ unsigned char *p = (unsigned char *)&port;
|
||
|
|
||
|
- if (ftpfs_command (me, super, WAIT_REPLY, "PORT %d,%d,%d,%d,%d,%d", a[0], a[1],
|
||
|
- a[2], a[3], p[0], p[1]) == COMPLETE)
|
||
|
- return data;
|
||
|
+ if (ftpfs_command (me, super, WAIT_REPLY, "PORT %u,%u,%u,%u,%u,%u", a[0], a[1], a[2], a[3],
|
||
|
+ p[0], p[1]) == COMPLETE)
|
||
|
+ return data_sock;
|
||
|
+ }
|
||
|
}
|
||
|
- close (data);
|
||
|
- ftpfs_errno = EIO;
|
||
|
- return -1;
|
||
|
+
|
||
|
+ close (data_sock);
|
||
|
+ ftpfs_errno = EIO;
|
||
|
+ return -1;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
ftpfs_open_data_connection (struct vfs_class *me, struct vfs_s_super *super, const char *cmd,
|
||
|
const char *remote, int isbinary, int reget)
|
||
|
{
|
||
|
- struct sockaddr_in from;
|
||
|
+ struct sockaddr_storage from;
|
||
|
int s, j, data;
|
||
|
socklen_t fromlen = sizeof(from);
|
||
|
|
||
|
--- mc-2006-09-12-21/vfs/ftpfs.h.ipv6 2005-05-29 14:10:08.000000000 +0200
|
||
|
+++ mc-2006-09-12-21/vfs/ftpfs.h 2006-09-26 10:42:36.000000000 +0200
|
||
|
@@ -15,6 +15,9 @@ extern int ftpfs_first_cd_then_ls;
|
||
|
void ftpfs_init_passwd (void);
|
||
|
void init_ftpfs (void);
|
||
|
|
||
|
+#define FTP_INET 1
|
||
|
+#define FTP_INET6 2
|
||
|
+
|
||
|
#define OPT_FLUSH 1
|
||
|
#define OPT_IGNORE_ERROR 2
|
||
|
|