diff --git a/mc-ipv6.patch b/mc-ipv6.patch new file mode 100644 index 0000000..8421e35 --- /dev/null +++ b/mc-ipv6.patch @@ -0,0 +1,388 @@ +--- 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 (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 + diff --git a/mc.spec b/mc.spec index 12e996e..aa3c2b2 100644 --- a/mc.spec +++ b/mc.spec @@ -3,7 +3,7 @@ Summary: User-friendly text console file manager and visual shell Name: mc Version: 4.6.1a -Release: 28%{?dist} +Release: 29%{?dist} Epoch: 1 License: GPL Group: System Environment/Shells @@ -27,6 +27,7 @@ Patch11: mc-etcmc.patch Patch12: mc-exit.patch Patch13: mc-fishfix.patch Patch14: mc-utf8-8bit-hex.patch +Patch15: mc-ipv6.patch %description Midnight Commander is a visual shell much like a file manager, only @@ -52,6 +53,7 @@ specific files. %patch12 -p1 -b .exit %patch13 -p1 -b .fishfix %patch14 -p1 -b .8bit-hex +%patch15 -p1 -b .ipv6 # convert files in /lib to UTF-8 pushd lib @@ -196,6 +198,10 @@ rm -rf $RPM_BUILD_ROOT %dir %{_sysconfdir}/mc %changelog +* Tue Sep 26 2006 Jindrich Novy 4.6.1a-29 +- add experimental IPv6 support for ftpfs (#198386), thanks to + Dan Kopecek for the patch + * Wed Sep 13 2006 Jindrich Novy 4.6.1a-28.fc6 - update to new CVS snapshot (09-12-21) - drop .assembly, .spec patches -> applied upstream