8001318: Socket.getLocalAddress not consistent with InetAddress.getLocalHost
authorkhazra
Thu, 28 Mar 2013 14:34:18 -0700
changeset 18212 22f8c33b0690
parent 18211 74aeb4741e3d
child 18213 45c8ed869a1b
8001318: Socket.getLocalAddress not consistent with InetAddress.getLocalHost Reviewed-by: alanb, chegar, hawtin
jdk/src/share/classes/java/net/ServerSocket.java
jdk/src/share/classes/java/net/Socket.java
jdk/src/share/classes/java/net/SocksSocketImpl.java
jdk/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java
jdk/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java
jdk/src/share/classes/java/nio/channels/DatagramChannel.java
jdk/src/share/classes/java/nio/channels/NetworkChannel.java
jdk/src/share/classes/java/nio/channels/ServerSocketChannel.java
jdk/src/share/classes/java/nio/channels/SocketChannel.java
jdk/src/share/classes/sun/net/NetworkClient.java
jdk/src/share/classes/sun/net/ftp/impl/FtpClient.java
jdk/src/share/classes/sun/net/httpserver/ServerImpl.java
jdk/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java
jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java
jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java
jdk/src/share/classes/sun/nio/ch/Net.java
jdk/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java
jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
jdk/src/share/classes/sun/nio/ch/SocketAdaptor.java
jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java
jdk/src/share/classes/sun/rmi/server/Activation.java
jdk/src/share/classes/sun/rmi/transport/proxy/WrappedSocket.java
jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java
jdk/src/solaris/classes/sun/nio/ch/sctp/SctpNet.java
jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java
--- a/jdk/src/share/classes/java/net/ServerSocket.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/java/net/ServerSocket.java	Thu Mar 28 14:34:18 2013 -0700
@@ -390,15 +390,29 @@
      * If the socket was bound prior to being {@link #close closed},
      * then this method will continue to return the local address
      * after the socket is closed.
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * the {@link InetAddress#getLoopbackAddress loopback} address is returned.
      *
      * @return  the address to which this socket is bound,
-     *          or <code>null</code> if the socket is unbound.
+     *          or the loopback address if denied by the security manager,
+     *          or {@code null} if the socket is unbound.
+     *
+     * @see SecurityManager#checkConnect
      */
     public InetAddress getInetAddress() {
         if (!isBound())
             return null;
         try {
-            return getImpl().getInetAddress();
+            InetAddress in = getImpl().getInetAddress();
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null)
+                sm.checkConnect(in.getHostAddress(), -1);
+            return in;
+        } catch (SecurityException e) {
+            return InetAddress.getLoopbackAddress();
         } catch (SocketException e) {
             // nothing
             // If we're bound, the impl has been created
@@ -431,18 +445,28 @@
     }
 
     /**
-     * Returns the address of the endpoint this socket is bound to, or
-     * <code>null</code> if it is not bound yet.
+     * Returns the address of the endpoint this socket is bound to.
      * <p>
      * If the socket was bound prior to being {@link #close closed},
      * then this method will continue to return the address of the endpoint
      * after the socket is closed.
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * a {@code SocketAddress} representing the
+     * {@link InetAddress#getLoopbackAddress loopback} address and the local
+     * port to which the socket is bound is returned.
      *
-     * @return a <code>SocketAddress</code> representing the local endpoint of this
-     *         socket, or <code>null</code> if it is not bound yet.
+     * @return a {@code SocketAddress} representing the local endpoint of
+     *         this socket, or a {@code SocketAddress} representing the
+     *         loopback address if denied by the security manager,
+     *         or {@code null} if the socket is not bound yet.
+     *
      * @see #getInetAddress()
      * @see #getLocalPort()
      * @see #bind(SocketAddress)
+     * @see SecurityManager#checkConnect
      * @since 1.4
      */
 
@@ -708,13 +732,25 @@
     /**
      * Returns the implementation address and implementation port of
      * this socket as a <code>String</code>.
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * an {@code InetAddress} representing the
+     * {@link InetAddress#getLoopbackAddress loopback} address is returned as
+     * the implementation address.
      *
      * @return  a string representation of this socket.
      */
     public String toString() {
         if (!isBound())
             return "ServerSocket[unbound]";
-        return "ServerSocket[addr=" + impl.getInetAddress() +
+        InetAddress in;
+        if (System.getSecurityManager() != null)
+            in = InetAddress.getLoopbackAddress();
+        else
+            in = impl.getInetAddress();
+        return "ServerSocket[addr=" + in +
                 ",localport=" + impl.getLocalPort()  + "]";
     }
 
--- a/jdk/src/share/classes/java/net/Socket.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/java/net/Socket.java	Thu Mar 28 14:34:18 2013 -0700
@@ -682,11 +682,18 @@
 
     /**
      * Gets the local address to which the socket is bound.
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * the {@link InetAddress#getLoopbackAddress loopback} address is returned.
      *
-     * @return the local address to which the socket is bound, or
-     *         the {@link InetAddress#isAnyLocalAddress wildcard} address
-     *         if the socket is closed or not bound yet.
+     * @return the local address to which the socket is bound,
+     *         the loopback address if denied by the security manager, or
+     *         the wildcard address if the socket is closed or not bound yet.
      * @since   JDK1.1
+     *
+     * @see SecurityManager#checkConnect
      */
     public InetAddress getLocalAddress() {
         // This is for backward compatibility
@@ -695,9 +702,14 @@
         InetAddress in = null;
         try {
             in = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null)
+                sm.checkConnect(in.getHostAddress(), -1);
             if (in.isAnyLocalAddress()) {
                 in = InetAddress.anyLocalAddress();
             }
+        } catch (SecurityException e) {
+            in = InetAddress.getLoopbackAddress();
         } catch (Exception e) {
             in = InetAddress.anyLocalAddress(); // "0.0.0.0"
         }
@@ -770,8 +782,7 @@
     }
 
     /**
-     * Returns the address of the endpoint this socket is bound to, or
-     * <code>null</code> if it is not bound yet.
+     * Returns the address of the endpoint this socket is bound to.
      * <p>
      * If a socket bound to an endpoint represented by an
      * <code>InetSocketAddress </code> is {@link #close closed},
@@ -780,12 +791,23 @@
      * <code>InetSocketAddress</code>'s address is the
      * {@link InetAddress#isAnyLocalAddress wildcard} address
      * and its port is the local port that it was bound to.
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * a {@code SocketAddress} representing the
+     * {@link InetAddress#getLoopbackAddress loopback} address and the local
+     * port to which this socket is bound is returned.
      *
-     * @return a <code>SocketAddress</code> representing the local endpoint of this
-     *         socket, or <code>null</code> if it is not bound yet.
+     * @return a {@code SocketAddress} representing the local endpoint of
+     *         this socket, or a {@code SocketAddress} representing the
+     *         loopback address if denied by the security manager, or
+     *         {@code null} if the socket is not bound yet.
+     *
      * @see #getLocalAddress()
      * @see #getLocalPort()
      * @see #bind(SocketAddress)
+     * @see SecurityManager#checkConnect
      * @since 1.4
      */
 
--- a/jdk/src/share/classes/java/net/SocksSocketImpl.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/java/net/SocksSocketImpl.java	Thu Mar 28 14:34:18 2013 -0700
@@ -28,6 +28,7 @@
 import java.io.OutputStream;
 import java.io.BufferedOutputStream;
 import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.security.PrivilegedExceptionAction;
 import sun.net.SocksProxy;
 import sun.net.www.ParseUtil;
@@ -590,7 +591,13 @@
         /* Test for AnyLocal */
         InetAddress naddr = baddr;
         if (naddr.isAnyLocalAddress()) {
-            naddr = cmdsock.getLocalAddress();
+            naddr = AccessController.doPrivileged(
+                        new PrivilegedAction<InetAddress>() {
+                            public InetAddress run() {
+                                return cmdsock.getLocalAddress();
+
+                            }
+                        });
             addr1 = naddr.getAddress();
         }
         out.write(PROTO_VERS4);
--- a/jdk/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java	Thu Mar 28 14:34:18 2013 -0700
@@ -297,4 +297,25 @@
      *          If this channel's socket has not yet been bound
      */
     public abstract Future<AsynchronousSocketChannel> accept();
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * a {@code SocketAddress} representing the
+     * {@link java.net.InetAddress#getLoopbackAddress loopback} address and the
+     * local port of the channel's socket is returned.
+     *
+     * @return  The {@code SocketAddress} that the socket is bound to, or the
+     *          {@code SocketAddress} representing the loopback address if
+     *          denied by the security manager, or {@code null} if the
+     *          channel's socket is not bound
+     *
+     * @throws  ClosedChannelException     {@inheritDoc}
+     * @throws  IOException                {@inheritDoc}
+     */
+    @Override
+    public abstract SocketAddress getLocalAddress() throws IOException;
 }
--- a/jdk/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java	Thu Mar 28 14:34:18 2013 -0700
@@ -645,4 +645,24 @@
                                    TimeUnit unit,
                                    A attachment,
                                    CompletionHandler<Long,? super A> handler);
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * a {@code SocketAddress} representing the
+     * {@link java.net.InetAddress#getLoopbackAddress loopback} address and the
+     * local port of the channel's socket is returned.
+     *
+     * @return  The {@code SocketAddress} that the socket is bound to, or the
+     *          {@code SocketAddress} representing the loopback address if
+     *          denied by the security manager, or {@code null} if the
+     *          channel's socket is not bound
+     *
+     * @throws  ClosedChannelException     {@inheritDoc}
+     * @throws  IOException                {@inheritDoc}
+     */
+    public abstract SocketAddress getLocalAddress() throws IOException;
 }
--- a/jdk/src/share/classes/java/nio/channels/DatagramChannel.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/java/nio/channels/DatagramChannel.java	Thu Mar 28 14:34:18 2013 -0700
@@ -565,4 +565,25 @@
         return write(srcs, 0, srcs.length);
     }
 
+    /**
+     * {@inheritDoc}
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * a {@code SocketAddress} representing the
+     * {@link java.net.InetAddress#getLoopbackAddress loopback} address and the
+     * local port of the channel's socket is returned.
+     *
+     * @return  The {@code SocketAddress} that the socket is bound to, or the
+     *          {@code SocketAddress} representing the loopback address if
+     *          denied by the security manager, or {@code null} if the
+     *          channel's socket is not bound
+     *
+     * @throws  ClosedChannelException     {@inheritDoc}
+     * @throws  IOException                {@inheritDoc}
+     */
+    @Override
+    public abstract SocketAddress getLocalAddress() throws IOException;
+
 }
--- a/jdk/src/share/classes/java/nio/channels/NetworkChannel.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/java/nio/channels/NetworkChannel.java	Thu Mar 28 14:34:18 2013 -0700
@@ -87,8 +87,7 @@
     NetworkChannel bind(SocketAddress local) throws IOException;
 
     /**
-     * Returns the socket address that this channel's socket is bound to, or
-     * {@code null} if the socket is not bound.
+     * Returns the socket address that this channel's socket is bound to.
      *
      * <p> Where the channel is {@link #bind bound} to an Internet Protocol
      * socket address then the return value from this method is of type {@link
--- a/jdk/src/share/classes/java/nio/channels/ServerSocketChannel.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/java/nio/channels/ServerSocketChannel.java	Thu Mar 28 14:34:18 2013 -0700
@@ -265,4 +265,25 @@
      */
     public abstract SocketChannel accept() throws IOException;
 
+    /**
+     * {@inheritDoc}
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * a {@code SocketAddress} representing the
+     * {@link java.net.InetAddress#getLoopbackAddress loopback} address and the
+     * local port of the channel's socket is returned.
+     *
+     * @return  The {@code SocketAddress} that the socket is bound to, or the
+     *          {@code SocketAddress} representing the loopback address if
+     *          denied by the security manager, or {@code null} if the
+     *          channel's socket is not bound
+     *
+     * @throws  ClosedChannelException     {@inheritDoc}
+     * @throws  IOException                {@inheritDoc}
+     */
+    @Override
+    public abstract SocketAddress getLocalAddress() throws IOException;
+
 }
--- a/jdk/src/share/classes/java/nio/channels/SocketChannel.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/java/nio/channels/SocketChannel.java	Thu Mar 28 14:34:18 2013 -0700
@@ -493,4 +493,25 @@
         return write(srcs, 0, srcs.length);
     }
 
+    /**
+     * {@inheritDoc}
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * a {@code SocketAddress} representing the
+     * {@link java.net.InetAddress#getLoopbackAddress loopback} address and the
+     * local port of the channel's socket is returned.
+     *
+     * @return  The {@code SocketAddress} that the socket is bound to, or the
+     *          {@code SocketAddress} representing the loopback address if
+     *          denied by the security manager, or {@code null} if the
+     *          channel's socket is not bound
+     *
+     * @throws  ClosedChannelException     {@inheritDoc}
+     * @throws  IOException                {@inheritDoc}
+     */
+    @Override
+    public abstract SocketAddress getLocalAddress() throws IOException;
+
 }
--- a/jdk/src/share/classes/sun/net/NetworkClient.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/sun/net/NetworkClient.java	Thu Mar 28 14:34:18 2013 -0700
@@ -200,7 +200,13 @@
     protected InetAddress getLocalAddress() throws IOException {
         if (serverSocket == null)
             throw new IOException("not connected");
-        return serverSocket.getLocalAddress();
+        return  AccessController.doPrivileged(
+                        new PrivilegedAction<InetAddress>() {
+                            public InetAddress run() {
+                                return serverSocket.getLocalAddress();
+
+                            }
+                        });
     }
 
     /** Close an open connection to the server. */
--- a/jdk/src/share/classes/sun/net/ftp/impl/FtpClient.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/sun/net/ftp/impl/FtpClient.java	Thu Mar 28 14:34:18 2013 -0700
@@ -76,7 +76,10 @@
     private FtpReplyCode lastReplyCode = null;
     /** Welcome message from the server, if any. */
     private String welcomeMsg;
-    private boolean passiveMode = true;
+    /**
+     * Only passive mode used in JDK. See Bug 8010784.
+     */
+    private final boolean passiveMode = true;
     private TransferType type = TransferType.BINARY;
     private long restartOffset = 0;
     private long lastTransSize = -1; // -1 means 'unknown size'
@@ -645,9 +648,18 @@
         } else {
             s = new Socket();
         }
+
+        InetAddress serverAddress = AccessController.doPrivileged(
+                new PrivilegedAction<InetAddress>() {
+                    @Override
+                    public InetAddress run() {
+                        return server.getLocalAddress();
+                    }
+                });
+
         // Bind the socket to the same address as the control channel. This
         // is needed in case of multi-homed systems.
-        s.bind(new InetSocketAddress(server.getLocalAddress(), 0));
+        s.bind(new InetSocketAddress(serverAddress, 0));
         if (connectTimeout >= 0) {
             s.connect(dest, connectTimeout);
         } else {
@@ -816,7 +828,9 @@
      * @see #setActiveMode()
      */
     public sun.net.ftp.FtpClient enablePassiveMode(boolean passive) {
-        passiveMode = passive;
+
+        // Only passive mode used in JDK. See Bug 8010784.
+        // passiveMode = passive;
         return this;
     }
 
--- a/jdk/src/share/classes/sun/net/httpserver/ServerImpl.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/sun/net/httpserver/ServerImpl.java	Thu Mar 28 14:34:18 2013 -0700
@@ -34,6 +34,8 @@
 import java.util.logging.Level;
 import javax.net.ssl.*;
 import com.sun.net.httpserver.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import sun.net.httpserver.HttpConnection.State;
 
 /**
@@ -244,7 +246,14 @@
     }
 
     public InetSocketAddress getAddress() {
-        return (InetSocketAddress)schan.socket().getLocalSocketAddress();
+        return AccessController.doPrivileged(
+                new PrivilegedAction<InetSocketAddress>() {
+                    public InetSocketAddress run() {
+                        return
+                            (InetSocketAddress)schan.socket()
+                                .getLocalSocketAddress();
+                    }
+                });
     }
 
     Selector getSelector () {
--- a/jdk/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java	Thu Mar 28 14:34:18 2013 -0700
@@ -51,7 +51,7 @@
     protected final FileDescriptor fd;
 
     // the local address to which the channel's socket is bound
-    protected volatile SocketAddress localAddress = null;
+    protected volatile InetSocketAddress localAddress = null;
 
     // need this lock to set local address
     private final Object stateLock = new Object();
@@ -173,7 +173,7 @@
     public final SocketAddress getLocalAddress() throws IOException {
         if (!isOpen())
             throw new ClosedChannelException();
-        return localAddress;
+        return Net.getRevealedLocalAddress(localAddress);
     }
 
     @Override
@@ -251,7 +251,7 @@
             if (localAddress == null) {
                 sb.append("unbound");
             } else {
-                sb.append(localAddress.toString());
+                sb.append(Net.getRevealedLocalAddressAsString(localAddress));
             }
         }
         sb.append(']');
--- a/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java	Thu Mar 28 14:34:18 2013 -0700
@@ -53,8 +53,8 @@
     // protects state, localAddress, and remoteAddress
     protected final Object stateLock = new Object();
 
-    protected volatile SocketAddress localAddress = null;
-    protected volatile SocketAddress remoteAddress = null;
+    protected volatile InetSocketAddress localAddress = null;
+    protected volatile InetSocketAddress remoteAddress = null;
 
     // State, increases monotonically
     static final int ST_UNINITIALIZED = -1;
@@ -442,7 +442,7 @@
     public final SocketAddress getLocalAddress() throws IOException {
         if (!isOpen())
             throw new ClosedChannelException();
-        return localAddress;
+         return Net.getRevealedLocalAddress(localAddress);
     }
 
     @Override
@@ -582,7 +582,8 @@
                 }
                 if (localAddress != null) {
                     sb.append(" local=");
-                    sb.append(localAddress.toString());
+                    sb.append(
+                            Net.getRevealedLocalAddressAsString(localAddress));
                 }
                 if (remoteAddress != null) {
                     sb.append(" remote=");
--- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java	Thu Mar 28 14:34:18 2013 -0700
@@ -85,8 +85,8 @@
     private int state = ST_UNINITIALIZED;
 
     // Binding
-    private SocketAddress localAddress;
-    private SocketAddress remoteAddress;
+    private InetSocketAddress localAddress;
+    private InetSocketAddress remoteAddress;
 
     // Our socket adaptor, if any
     private DatagramSocket socket;
@@ -168,7 +168,8 @@
         synchronized (stateLock) {
             if (!isOpen())
                 throw new ClosedChannelException();
-            return localAddress;
+            // Perform security check before returning address
+            return Net.getRevealedLocalAddress(localAddress);
         }
     }
 
@@ -721,6 +722,7 @@
         }
     }
 
+    @Override
     public DatagramChannel connect(SocketAddress sa) throws IOException {
         int localPort = 0;
 
@@ -742,7 +744,7 @@
 
                     // Connection succeeded; disallow further invocation
                     state = ST_CONNECTED;
-                    remoteAddress = sa;
+                    remoteAddress = isa;
                     sender = isa;
                     cachedSenderInetAddress = isa.getAddress();
                     cachedSenderPort = isa.getPort();
@@ -761,7 +763,7 @@
                 synchronized (stateLock) {
                     if (!isConnected() || !isOpen())
                         return this;
-                    InetSocketAddress isa = (InetSocketAddress)remoteAddress;
+                    InetSocketAddress isa = remoteAddress;
                     SecurityManager sm = System.getSecurityManager();
                     if (sm != null)
                         sm.checkConnect(isa.getAddress().getHostAddress(),
--- a/jdk/src/share/classes/sun/nio/ch/Net.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/sun/nio/ch/Net.java	Thu Mar 28 14:34:18 2013 -0700
@@ -31,6 +31,7 @@
 import java.util.*;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
 
 
 public class Net {
@@ -183,6 +184,34 @@
     }
 
     /**
+     * Returns the local address after performing a SecurityManager#checkConnect.
+     */
+    static InetSocketAddress getRevealedLocalAddress(InetSocketAddress addr) {
+        SecurityManager sm = System.getSecurityManager();
+        if (addr == null || sm == null)
+            return addr;
+
+        try{
+            sm.checkConnect(addr.getAddress().getHostAddress(), -1);
+            // Security check passed
+        } catch (SecurityException e) {
+            // Return loopback address only if security check fails
+            addr = getLoopbackAddress(addr.getPort());
+        }
+        return addr;
+    }
+
+    static String getRevealedLocalAddressAsString(InetSocketAddress addr) {
+        return System.getSecurityManager() == null ? addr.toString() :
+                getLoopbackAddress(addr.getPort()).toString();
+    }
+
+    private static InetSocketAddress getLoopbackAddress(int port) {
+        return new InetSocketAddress(InetAddress.getLoopbackAddress(),
+                                     port);
+    }
+
+    /**
      * Returns any IPv4 address of the given network interface, or
      * null if the interface does not have any IPv4 addresses.
      */
--- a/jdk/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java	Thu Mar 28 14:34:18 2013 -0700
@@ -80,7 +80,8 @@
     public InetAddress getInetAddress() {
         if (!ssc.isBound())
             return null;
-        return Net.asInetSocketAddress(ssc.localAddress()).getAddress();
+        return Net.getRevealedLocalAddress(ssc.localAddress()).getAddress();
+
     }
 
     public int getLocalPort() {
--- a/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Thu Mar 28 14:34:18 2013 -0700
@@ -72,7 +72,7 @@
     private int state = ST_UNINITIALIZED;
 
     // Binding
-    private SocketAddress localAddress; // null => unbound
+    private InetSocketAddress localAddress; // null => unbound
 
     // set true when exclusive binding is on and SO_REUSEADDR is emulated
     private boolean isReuseAddress;
@@ -116,7 +116,9 @@
         synchronized (stateLock) {
             if (!isOpen())
                 throw new ClosedChannelException();
-            return localAddress;
+            return localAddress == null ? localAddress
+                    : Net.getRevealedLocalAddress(
+                          Net.asInetSocketAddress(localAddress));
         }
     }
 
@@ -190,7 +192,7 @@
         }
     }
 
-    public SocketAddress localAddress() {
+    public InetSocketAddress localAddress() {
         synchronized (stateLock) {
             return localAddress;
         }
@@ -384,14 +386,15 @@
         StringBuffer sb = new StringBuffer();
         sb.append(this.getClass().getName());
         sb.append('[');
-        if (!isOpen())
+        if (!isOpen()) {
             sb.append("closed");
-        else {
+        } else {
             synchronized (stateLock) {
-                if (localAddress() == null) {
+                InetSocketAddress addr = localAddress();
+                if (addr == null) {
                     sb.append("unbound");
                 } else {
-                    sb.append(localAddress().toString());
+                    sb.append(Net.getRevealedLocalAddressAsString(addr));
                 }
             }
         }
--- a/jdk/src/share/classes/sun/nio/ch/SocketAdaptor.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/sun/nio/ch/SocketAdaptor.java	Thu Mar 28 14:34:18 2013 -0700
@@ -149,9 +149,10 @@
 
     public InetAddress getLocalAddress() {
         if (sc.isOpen()) {
-            SocketAddress local = sc.localAddress();
-            if (local != null)
-                return ((InetSocketAddress)local).getAddress();
+            InetSocketAddress local = sc.localAddress();
+            if (local != null) {
+                return Net.getRevealedLocalAddress(local).getAddress();
+            }
         }
         return new InetSocketAddress(0).getAddress();
     }
--- a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java	Thu Mar 28 14:34:18 2013 -0700
@@ -83,8 +83,8 @@
     private int state = ST_UNINITIALIZED;
 
     // Binding
-    private SocketAddress localAddress;
-    private SocketAddress remoteAddress;
+    private InetSocketAddress localAddress;
+    private InetSocketAddress remoteAddress;
 
     // Input/Output open
     private boolean isInputOpen = true;
@@ -146,7 +146,7 @@
         synchronized (stateLock) {
             if (!isOpen())
                 throw new ClosedChannelException();
-            return localAddress;
+            return  Net.getRevealedLocalAddress(localAddress);
         }
     }
 
@@ -547,7 +547,7 @@
         IOUtil.configureBlocking(fd, block);
     }
 
-    public SocketAddress localAddress() {
+    public InetSocketAddress localAddress() {
         synchronized (stateLock) {
             return localAddress;
         }
@@ -974,6 +974,7 @@
         return fdVal;
     }
 
+    @Override
     public String toString() {
         StringBuffer sb = new StringBuffer();
         sb.append(this.getClass().getSuperclass().getName());
@@ -997,9 +998,10 @@
                         sb.append(" oshut");
                     break;
                 }
-                if (localAddress() != null) {
+                InetSocketAddress addr = localAddress();
+                if (addr != null) {
                     sb.append(" local=");
-                    sb.append(localAddress().toString());
+                    sb.append(Net.getRevealedLocalAddressAsString(addr));
                 }
                 if (remoteAddress() != null) {
                     sb.append(" remote=");
--- a/jdk/src/share/classes/sun/rmi/server/Activation.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/sun/rmi/server/Activation.java	Thu Mar 28 14:34:18 2013 -0700
@@ -2230,7 +2230,13 @@
         }
 
         public InetAddress getInetAddress() {
-            return serverSocket.getInetAddress();
+            return AccessController.doPrivileged(
+                new PrivilegedAction<InetAddress>() {
+                    @Override
+                    public InetAddress run() {
+                        return serverSocket.getInetAddress();
+                    }
+                });
         }
 
         public int getLocalPort() {
@@ -2238,7 +2244,13 @@
         }
 
         public SocketAddress getLocalSocketAddress() {
-            return serverSocket.getLocalSocketAddress();
+            return AccessController.doPrivileged(
+                new PrivilegedAction<SocketAddress>() {
+                    @Override
+                    public SocketAddress run() {
+                        return serverSocket.getLocalSocketAddress();
+                    }
+                });
         }
 
         /**
--- a/jdk/src/share/classes/sun/rmi/transport/proxy/WrappedSocket.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/share/classes/sun/rmi/transport/proxy/WrappedSocket.java	Thu Mar 28 14:34:18 2013 -0700
@@ -28,6 +28,8 @@
 import java.net.InetAddress;
 import java.net.Socket;
 import java.net.SocketException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 
 /**
  * The WrappedSocket class provides a general wrapper for providing an
@@ -78,7 +80,14 @@
      * Get the local address to which the socket is bound.
      */
     public InetAddress getLocalAddress() {
-        return socket.getLocalAddress();
+        return  AccessController.doPrivileged(
+                        new PrivilegedAction<InetAddress>() {
+                            @Override
+                            public InetAddress run() {
+                                return socket.getLocalAddress();
+
+                            }
+                        });
     }
 
     /**
--- a/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java	Thu Mar 28 14:34:18 2013 -0700
@@ -241,7 +241,7 @@
         synchronized (stateLock) {
             state = ST_CONNECTED;
             localAddress = Net.localAddress(fd);
-            remoteAddress = pendingRemote;
+            remoteAddress = (InetSocketAddress)pendingRemote;
         }
     }
 
--- a/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpNet.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpNet.java	Thu Mar 28 14:34:18 2013 -0700
@@ -94,18 +94,44 @@
 
     static Set<SocketAddress> getLocalAddresses(int fd)
             throws IOException {
-        HashSet<SocketAddress> set = null;
+        Set<SocketAddress> set = null;
         SocketAddress[] saa = getLocalAddresses0(fd);
 
         if (saa != null) {
-            set = new HashSet<SocketAddress>(saa.length);
-            for (SocketAddress sa : saa)
-                set.add(sa);
+            set = getRevealedLocalAddressSet(saa);
         }
 
         return set;
     }
 
+    private static Set<SocketAddress> getRevealedLocalAddressSet(
+            SocketAddress[] saa)
+    {
+         SecurityManager sm = System.getSecurityManager();
+         Set<SocketAddress> set = new HashSet<>(saa.length);
+         for (SocketAddress sa : saa) {
+             set.add(getRevealedLocalAddress(sa, sm));
+         }
+         return set;
+    }
+
+    private static SocketAddress getRevealedLocalAddress(SocketAddress sa,
+                                                         SecurityManager sm)
+    {
+        if (sm == null || sa == null)
+            return sa;
+        InetSocketAddress ia = (InetSocketAddress)sa;
+        try{
+            sm.checkConnect(ia.getAddress().getHostAddress(), -1);
+            // Security check passed
+        } catch (SecurityException e) {
+            // Return loopback address
+            return new InetSocketAddress(InetAddress.getLoopbackAddress(),
+                                         ia.getPort());
+        }
+        return sa;
+    }
+
     static Set<SocketAddress> getRemoteAddresses(int fd, int assocId)
             throws IOException {
         HashSet<SocketAddress> set = null;
--- a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java	Thu Mar 28 06:55:42 2013 -0400
+++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java	Thu Mar 28 14:34:18 2013 -0700
@@ -137,7 +137,9 @@
 
     // invoked by WindowsAsynchronousServerSocketChannelImpl when new connection
     // accept
-    void setConnected(SocketAddress localAddress, SocketAddress remoteAddress) {
+    void setConnected(InetSocketAddress localAddress,
+                      InetSocketAddress remoteAddress)
+    {
         synchronized (stateLock) {
             state = ST_CONNECTED;
             this.localAddress = localAddress;