diff --git a/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java b/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java
index 3137f740593..560fbfbea94 100644
--- a/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java
+++ b/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java
@@ -24,16 +24,36 @@
  */
 package sun.net.ftp.impl;
 
-import java.net.*;
-import java.io.*;
+
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
 import java.text.DateFormat;
 import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeParseException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Base64;
 import java.util.Calendar;
 import java.util.Date;
@@ -44,7 +64,11 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import javax.net.ssl.SSLSocket;
 import javax.net.ssl.SSLSocketFactory;
-import sun.net.ftp.*;
+import sun.net.ftp.FtpDirEntry;
+import sun.net.ftp.FtpDirParser;
+import sun.net.ftp.FtpProtocolException;
+import sun.net.ftp.FtpReplyCode;
+import sun.net.util.IPAddressUtil;
 import sun.util.logging.PlatformLogger;
 
 
@@ -107,13 +131,15 @@ public class FtpClient extends sun.net.ftp.FtpClient {
     private static Pattern[] patterns;
     private static Pattern linkp = Pattern.compile("(\\p{Print}+) \\-\\> (\\p{Print}+)$");
     private DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, java.util.Locale.US);
-
+    private static final boolean acceptPasvAddressVal;
     static {
         final int vals[] = {0, 0};
+        final String acceptPasvAddress[] = {null};
         @SuppressWarnings("removal")
         final String enc = AccessController.doPrivileged(
                 new PrivilegedAction<String>() {
                     public String run() {
+                        acceptPasvAddress[0] = System.getProperty("jdk.net.ftp.trustPasvAddress", "false");
                         vals[0] = Integer.getInteger("sun.net.client.defaultReadTimeout", 300_000).intValue();
                         vals[1] = Integer.getInteger("sun.net.client.defaultConnectTimeout", 300_000).intValue();
                         return System.getProperty("file.encoding", "ISO8859_1");
@@ -144,6 +170,8 @@ public class FtpClient extends sun.net.ftp.FtpClient {
         for (int i = 0; i < patStrings.length; i++) {
             patterns[i] = Pattern.compile(patStrings[i]);
         }
+
+        acceptPasvAddressVal = Boolean.parseBoolean(acceptPasvAddress[0]);
     }
 
     /**
@@ -610,7 +638,6 @@ public class FtpClient extends sun.net.ftp.FtpClient {
             //
             // The regular expression is a bit more complex this time, because
             // the parenthesis are optionals and we have to use 3 groups.
-
             if (pasvPat == null) {
                 pasvPat = Pattern.compile("227 .* \\(?(\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3}),(\\d{1,3}),(\\d{1,3})\\)?");
             }
@@ -622,8 +649,15 @@ public class FtpClient extends sun.net.ftp.FtpClient {
             port = Integer.parseInt(m.group(3)) + (Integer.parseInt(m.group(2)) << 8);
             // IP address is simple
             String s = m.group(1).replace(',', '.');
-            dest = new InetSocketAddress(s, port);
+            if (!IPAddressUtil.isIPv4LiteralAddress(s))
+                throw new FtpProtocolException("PASV failed : "  + serverAnswer);
+            if (acceptPasvAddressVal) {
+                dest = new InetSocketAddress(s, port);
+            } else {
+                dest = validatePasvAddress(port, s, server.getInetAddress());
+            }
         }
+
         // Got everything, let's open the socket!
         Socket s;
         if (proxy != null) {
@@ -678,6 +712,80 @@ public class FtpClient extends sun.net.ftp.FtpClient {
         return s;
     }
 
+    static final String ERROR_MSG = "Address should be the same as originating server";
+
+    /**
+     * Returns an InetSocketAddress, based on value of acceptPasvAddressVal
+     * and other conditions such as the server address returned by pasv
+     * is not a hostname, is a socks proxy, or the loopback. An exception
+     * is thrown if none of the valid conditions are met.
+     */
+    private InetSocketAddress validatePasvAddress(int port, String s, InetAddress address)
+        throws FtpProtocolException
+    {
+        if (address == null) {
+            return InetSocketAddress.createUnresolved(serverAddr.getHostName(), port);
+        }
+        String serverAddress = address.getHostAddress();
+        if (serverAddress.equals(s)) {
+            return new InetSocketAddress(s, port);
+        } else if (address.isLoopbackAddress() && s.startsWith("127.")) { // can be 127.0
+            return new InetSocketAddress(s, port);
+        } else if (address.isLoopbackAddress()) {
+            if (privilegedLocalHost().getHostAddress().equals(s)) {
+                return new InetSocketAddress(s, port);
+            } else {
+                throw new FtpProtocolException(ERROR_MSG);
+            }
+        } else if (s.startsWith("127.")) {
+            if (privilegedLocalHost().equals(address)) {
+                return new InetSocketAddress(s, port);
+            } else {
+                throw new FtpProtocolException(ERROR_MSG);
+            }
+        }
+        String hostName = address.getHostName();
+        if (!(IPAddressUtil.isIPv4LiteralAddress(hostName) || IPAddressUtil.isIPv6LiteralAddress(hostName))) {
+            InetAddress[] names = privilegedGetAllByName(hostName);
+            String resAddress = Arrays
+                .stream(names)
+                .map(InetAddress::getHostAddress)
+                .filter(s::equalsIgnoreCase)
+                .findFirst()
+                .orElse(null);
+            if (resAddress != null) {
+                return new InetSocketAddress(s, port);
+            }
+        }
+        throw new FtpProtocolException(ERROR_MSG);
+    }
+
+    private static InetAddress privilegedLocalHost() throws FtpProtocolException {
+        PrivilegedExceptionAction<InetAddress> action = InetAddress::getLocalHost;
+        try {
+            @SuppressWarnings("removal")
+            var tmp = AccessController.doPrivileged(action);
+            return tmp;
+        } catch (Exception e) {
+            var ftpEx = new FtpProtocolException(ERROR_MSG);
+            ftpEx.initCause(e);
+            throw ftpEx;
+        }
+    }
+
+    private static InetAddress[] privilegedGetAllByName(String hostName) throws FtpProtocolException {
+        PrivilegedExceptionAction<InetAddress[]> pAction = () -> InetAddress.getAllByName(hostName);
+        try {
+            @SuppressWarnings("removal")
+            var tmp =AccessController.doPrivileged(pAction);
+            return tmp;
+        } catch (Exception e) {
+            var ftpEx = new FtpProtocolException(ERROR_MSG);
+            ftpEx.initCause(e);
+            throw ftpEx;
+        }
+    }
+
     /**
      * Opens a data connection with the server according to the set mode
      * (ACTIVE or PASSIVE) then send the command passed as an argument.
@@ -688,7 +796,6 @@ public class FtpClient extends sun.net.ftp.FtpClient {
      */
     private Socket openDataConnection(String cmd) throws sun.net.ftp.FtpProtocolException, IOException {
         Socket clientSocket;
-
         if (passiveMode) {
             try {
                 return openPassiveDataConnection(cmd);