--- 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; + /* (||||) */ + 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 (getpeername (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 --- mc-2006-08-12-18/vfs/utilvfs.c.ipv6 2006-01-30 18:01:58.000000000 +0100 +++ mc-2006-08-12-18/vfs/utilvfs.c 2010-12-14 20:41:09.000000000 +0100 @@ -109,7 +109,21 @@ vfs_split_url (const char *path, char ** } /* Check if the host comes with a port spec, if so, chop it */ - colon = strchr (rest, ':'); + if ('[' == *rest) { + colon = strchr (++rest, ']'); + if (colon) { + colon[0] = '\0'; + colon[1] = '\0'; + colon++; + } else { + g_free (pcopy); + *host = NULL; + *port = 0; + return NULL; + } + } else + colon = strchr (rest, ':'); + if (colon) { *colon = 0; if (sscanf (colon + 1, "%d", port) == 1) {