diff options
Diffstat (limited to 'usr.bin/ftp')
-rw-r--r-- | usr.bin/ftp/extern.h | 1 | ||||
-rw-r--r-- | usr.bin/ftp/fetch.c | 1 | ||||
-rw-r--r-- | usr.bin/ftp/ftp.c | 35 |
3 files changed, 37 insertions, 0 deletions
diff --git a/usr.bin/ftp/extern.h b/usr.bin/ftp/extern.h index d935d9e..54ccd79 100644 --- a/usr.bin/ftp/extern.h +++ b/usr.bin/ftp/extern.h @@ -41,6 +41,7 @@ void abortpt __P((int)); void abortrecv __P((int)); void abortsend __P((int)); void account __P((int, char **)); +void ai_unmapped __P((struct addrinfo *)); void alarmtimer __P((int)); int another __P((int *, char ***, const char *)); int auto_fetch __P((int, char **)); diff --git a/usr.bin/ftp/fetch.c b/usr.bin/ftp/fetch.c index f306406..0643e5d 100644 --- a/usr.bin/ftp/fetch.c +++ b/usr.bin/ftp/fetch.c @@ -217,6 +217,7 @@ url_get(origline, proxyenv) while (1) { + ai_unmapped(res); s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s == -1) { res = res->ai_next; diff --git a/usr.bin/ftp/ftp.c b/usr.bin/ftp/ftp.c index a4c350f..8d38669 100644 --- a/usr.bin/ftp/ftp.c +++ b/usr.bin/ftp/ftp.c @@ -139,6 +139,13 @@ hookup(host0, port) sizeof(hostnamebuf)); hostname = hostnamebuf; while (1) { + /* + * make sure that ai_addr is NOT an IPv4 mapped address. + * IPv4 mapped address complicates too many things in FTP + * protocol handling, as FTP protocol is defined differently + * between IPv4 and IPv6. + */ + ai_unmapped(res); s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) { res = res->ai_next; @@ -1928,3 +1935,31 @@ abort_remote(din) } (void)getreply(0); } + +void +ai_unmapped(ai) + 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; +} |