Hi again,

This commit rewrites the host checking in SocketPermission so it does
what the javadoc says it should.  (This is the end result of all my
InetAddress hacking this past couple of weeks.)  We now pass all the
SocketPermission mauve tests.

Cheers,
Gary
Index: ChangeLog
===================================================================
RCS file: /cvsroot/classpath/classpath/ChangeLog,v
retrieving revision 1.8543
diff -u -r1.8543 ChangeLog
--- ChangeLog   14 Sep 2006 10:35:48 -0000      1.8543
+++ ChangeLog   14 Sep 2006 13:37:30 -0000
@@ -1,3 +1,17 @@
+2006-09-14  Gary Benson  <[EMAIL PROTECTED]>
+
+       * java/net/InetAddress.java
+       (internalGetCanonicalHostName): New method.
+       (getCanonicalHostName): Use internalGetCanonicalHostName.
+       (getByLiteral): New method.
+       (getAllByName): Use getByLiteral.
+       * java/net/SocketPermission.java
+       (host): Replaced with...
+       (hostname, address): New fields.
+       (equals, hashcode): Reflect the above.
+       (setHostPort): Parse host into hostname or address.
+       (implies): Rewrite host checks.
+
 2006-09-14  David Gilbert  <[EMAIL PROTECTED]>
 
        Fixes PR28699
Index: java/net/InetAddress.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/net/InetAddress.java,v
retrieving revision 1.50
diff -u -r1.50 InetAddress.java
--- java/net/InetAddress.java   8 Sep 2006 14:33:31 -0000       1.50
+++ java/net/InetAddress.java   14 Sep 2006 13:37:31 -0000
@@ -311,20 +311,27 @@
 
   /**
    * Returns the canonical hostname represented by this InetAddress
-   * 
-   * @since 1.4
    */
-  public String getCanonicalHostName()
+  String internalGetCanonicalHostName()
   {
-    String hostname;
     try
       {
-       hostname = VMInetAddress.getHostByAddr(addr);
+       return VMInetAddress.getHostByAddr(addr);
       }
     catch (UnknownHostException e)
       {
        return getHostAddress();
       }
+  }
+
+  /**
+   * Returns the canonical hostname represented by this InetAddress
+   * 
+   * @since 1.4
+   */
+  public String getCanonicalHostName()
+  {
+    String hostname = internalGetCanonicalHostName();
 
     SecurityManager sm = System.getSecurityManager();
     if (sm != null)
@@ -492,6 +499,34 @@
   }
 
   /**
+   * Returns an InetAddress object representing the IP address of
+   * the given literal IP address in dotted decimal format such as
+   * "127.0.0.1".  This is used by SocketPermission.setHostPort()
+   * to parse literal IP addresses without performing a DNS lookup.
+   *
+   * @param literal The literal IP address to create the InetAddress
+   * object from
+   *
+   * @return The address of the host as an InetAddress object, or
+   * null if the IP address is invalid.
+   */
+  static InetAddress getByLiteral(String literal)
+  {
+    byte[] address = VMInetAddress.aton(literal);
+    if (address == null)
+      return null;
+    
+    try
+      {
+       return getByAddress(address);
+      }
+    catch (UnknownHostException e)
+      {
+       throw new RuntimeException("should never happen", e);
+      }
+  }
+
+  /**
    * Returns an InetAddress object representing the IP address of the given
    * hostname.  This name can be either a hostname such as 
"www.urbanophile.com"
    * or an IP address in dotted decimal format such as "127.0.0.1".  If the
@@ -542,9 +577,9 @@
       return new InetAddress[] {LOCALHOST};
 
     // Check if hostname is an IP address
-    byte[] address = VMInetAddress.aton(hostname);
+    InetAddress address = getByLiteral(hostname);
     if (address != null)
-      return new InetAddress[] {getByAddress(address)};
+      return new InetAddress[] {address};
 
     // Perform security check before resolving
     SecurityManager sm = System.getSecurityManager();
Index: java/net/SocketPermission.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/net/SocketPermission.java,v
retrieving revision 1.22
diff -u -r1.22 SocketPermission.java
--- java/net/SocketPermission.java      31 Aug 2006 12:26:22 -0000      1.22
+++ java/net/SocketPermission.java      14 Sep 2006 13:37:31 -0000
@@ -117,11 +117,18 @@
   static final long serialVersionUID = -7204263841984476862L;
 
   /**
-   * A hostname (possibly wildcarded) or IP address (IPv4 or IPv6).
+   * A hostname (possibly wildcarded).  Will be set if and only if
+   * this object was initialized with a hostname.
    */
-  private transient String host;
+  private transient String hostname = null;
 
   /**
+   * An IP address (IPv4 or IPv6).  Will be set if and only if this
+   * object was initialized with a single literal IP address.
+   */  
+  private transient InetAddress address = null;
+  
+  /**
    * A range of ports.
    */
   private transient int minport;
@@ -225,7 +232,7 @@
   private void setHostPort(String hostport)
   {
     // Split into host and ports
-    String ports;
+    String host, ports;
     if (hostport.charAt(0) == '[')
       {
        // host is a bracketed IPv6 address
@@ -234,6 +241,10 @@
          throw new IllegalArgumentException("Unmatched '['");
        host = hostport.substring(1, end);
 
+       address = InetAddress.getByLiteral(host);
+       if (address == null)
+         throw new IllegalArgumentException("Bad IPv6 address");
+
        if (end == hostport.length() - 1)
          ports = "";
        else if (hostport.charAt(end + 1) == ':')
@@ -255,6 +266,15 @@
            host = hostport.substring(0, sep);
            ports = hostport.substring(sep + 1);
          }
+
+       address = InetAddress.getByLiteral(host);
+       if (address == null)
+         {
+           if (host.lastIndexOf('*') > 0)
+             throw new IllegalArgumentException("Bad hostname");
+
+           hostname = host;
+         }
       }
 
     // Parse and validate the ports
@@ -362,10 +382,25 @@
     else
       return false;
 
-    return p.actionmask == actionmask &&
-      p.minport == minport &&
-      p.maxport == maxport &&
-      p.host.equals(host);
+    if (p.actionmask != actionmask ||
+       p.minport != minport ||
+       p.maxport != maxport)
+      return false;
+
+    if (address != null)
+      {
+       if (p.address == null)
+         return false;
+       else
+         return p.address.equals(address);
+      }
+    else
+      {
+       if (p.hostname == null)
+         return false;
+       else
+         return p.hostname.equals(hostname);
+      }
   }
 
   /**
@@ -376,7 +411,12 @@
    */
   public int hashCode()
   {
-    return actionmask + minport + maxport + host.hashCode();
+    int code = actionmask + minport + maxport;
+    if (address != null)
+      code += address.hashCode();
+    else
+      code += hostname.hashCode();
+    return code;
   }
 
   /**
@@ -416,6 +456,44 @@
   }
 
   /**
+   * Returns an array of all IP addresses represented by this object.
+   */
+  private InetAddress[] getAddresses()
+  {
+    if (address != null)
+      return new InetAddress[] {address};
+
+    try
+      {
+       return InetAddress.getAllByName(hostname);
+      }
+    catch (UnknownHostException e)
+      {
+       return new InetAddress[0];
+      }
+  }
+
+  /**
+   * Returns the canonical hostname represented by this object,
+   * or null if this object represents a wildcarded domain.
+   */
+  private String getCanonicalHostName()
+  {
+    if (address != null)
+      return address.internalGetCanonicalHostName();
+    if (hostname.charAt(0) == '*')
+      return null;
+    try
+      {
+       return InetAddress.getByName(hostname).internalGetCanonicalHostName();
+      }
+    catch (UnknownHostException e)
+      {
+       return null;
+      }
+  }
+  
+  /**
    * Returns true if the permission object passed it is implied by the
    * this permission.  This will be true if:
    * 
@@ -450,6 +528,11 @@
     else
       return false;
 
+    // If p was initialised with an empty hostname then we do not
+    // imply it. This is not part of the spec, but it seems necessary.
+    if (p.hostname != null && p.hostname.length() == 0)
+      return false;
+    
     // Next check the actions
     if ((p.actionmask & actionmask) != p.actionmask)
        return false;
@@ -459,36 +542,54 @@
       return false;
 
     // Finally check the hosts
-    if (host.equals(p.host))
-      return true;
+    String p_canon = null;
 
-    // Try the canonical names
-    String ourcanonical = null;
-    String theircanonical = null;
-    try
+    // Return true if this object was initialized with a single
+    // IP address which one of p's IP addresses is equal to.
+    if (address != null)
       {
-       ourcanonical = InetAddress.getByName(host).getHostName();
-       theircanonical = InetAddress.getByName(p.host).getHostName();
+       InetAddress[] addrs = p.getAddresses();
+       for (int i = 0; i < addrs.length; i++)
+         {
+           if (address.equals(addrs[i]))
+             return true;
+         }
       }
-    catch (UnknownHostException e)
+
+    // Return true if this object is a wildcarded domain that
+    // p's canonical name matches.
+    if (hostname != null && hostname.charAt(0) == '*')
+      {
+       p_canon = p.getCanonicalHostName();
+       if (p_canon != null && p_canon.endsWith(hostname.substring(1)))
+         return true;
+       
+      }
+
+    // Return true if this one of this object's IP addresses
+    // is equal to one of p's.
+    if (address == null)
       {
-       // Who didn't resolve?  Just assume current address is canonical enough
-       // Is this ok to do?
-       if (ourcanonical == null)
-         ourcanonical = host;
-       if (theircanonical == null)
-         theircanonical = p.host;
-      }
-
-    if (ourcanonical.equals(theircanonical))
-      return true;
-
-    // Well, last chance.  Try for a wildcard
-    if (host.indexOf("*.") != -1)
-      {
-       String wild_domain =
-         host.substring(host.indexOf("*" + 1));
-       if (theircanonical.endsWith(wild_domain))
+       InetAddress[] addrs = p.getAddresses();
+       InetAddress[] p_addrs = p.getAddresses();
+
+       for (int i = 0; i < addrs.length; i++)
+         {
+           for (int j = 0; j < p_addrs.length; j++)
+             {
+               if (addrs[i].equals(p_addrs[j]))
+                 return true;
+             }
+         }
+      }
+
+    // Return true if this object's canonical name equals p's.
+    String canon = getCanonicalHostName();
+    if (canon != null)
+      {
+       if (p_canon == null)
+         p_canon = p.getCanonicalHostName();
+       if (p_canon != null && canon.equals(p_canon))
          return true;
       }
 

Reply via email to