Bug 1287774 - ldapjdk needs to support IPv6 addresses
authorRich Megginson <richm@stanfordalumni.org>
Mon, 08 Aug 2016 16:00:49 -0600
changeset 46 f9d7552c8188
parent 45 0f7c3698a961
child 47 88f411aabcde
push id31
push userrichm@stanfordalumni.org
push dateMon, 08 Aug 2016 22:00:53 +0000
bugs1287774
Bug 1287774 - ldapjdk needs to support IPv6 addresses https://bugzilla.mozilla.org/show_bug.cgi?id=1287774 support IPv6 addresses in LDAP URLs
java-sdk/ldapjdk/netscape/ldap/LDAPConnection.java
java-sdk/ldapjdk/netscape/ldap/LDAPUrl.java
--- a/java-sdk/ldapjdk/netscape/ldap/LDAPConnection.java
+++ b/java-sdk/ldapjdk/netscape/ldap/LDAPConnection.java
@@ -874,22 +874,24 @@ public class LDAPConnection
      * specify the preferences for the bind operation.
      *<P>
      * You can limit the time spent waiting for the connection to be established
      * by calling <CODE>setConnectTimeout</CODE> before <CODE>connect</CODE>. 
      * <P>
      * @param host host name of the LDAP server to which you want to connect.
      * This value can also be a space-delimited list of hostnames or
      * hostnames and port numbers (using the syntax
-     * <I>hostname:portnumber</I>). For example, you can specify
-     * the following values for the <CODE>host</CODE> argument:<BR>
+     * <I>hostname:portnumber</I>). For IPv6 enclose the address in square brackets.
+     * For example, you can specify the following values for the 
+     * <CODE>host</CODE> argument:<BR>
      *<PRE>
      *   myhost
      *   myhost hishost:389 herhost:5000 whathost
      *   myhost:686 myhost:389 hishost:5000 whathost:1024
+     *   [::1]:389 [2620:52:0:102f:5054:1ff:fe2c:e12d]:636
      *</PRE>
      * If multiple servers are specified in the <CODE>host</CODE> list, the connection
      *  setup policy specified with the <CODE>ConnSetupDelay</CODE> property controls
      * whether connection attempts are made serially or concurrently.
      * <P>
      * @param port port number of the LDAP server to which you want to connect.
      * This parameter is ignored for any host in the <CODE>host</CODE>
      * parameter which includes a colon and port number.
@@ -929,23 +931,42 @@ public class LDAPConnection
         /* Parse the list of hosts */    
         int defaultPort = port;
         StringTokenizer st = new StringTokenizer( host );
         String hostList[] = new String[st.countTokens()];
         int portList[] = new int[st.countTokens()];
         int i = 0;
         while( st.hasMoreTokens() ) {
             String s = st.nextToken();
-            int colon = s.indexOf( ':' );
-            if ( colon > 0 ) {
-                hostList[i] = s.substring( 0, colon );
-                portList[i] = Integer.parseInt( s.substring( colon+1 ) );
+            int colon;
+            
+            if ( s.startsWith( "[" ) ) {
+                // We have an ipv6 address
+                int end = s.indexOf( ']' );
+                if ( end == -1 ) {
+                    throw new LDAPException ( "invalid URL for IPv6 address",
+                        LDAPException.PARAM_ERROR );
+                }
+                String remainder = s.substring( end+1 );
+                hostList[i] = s.substring( 0, end+1 );
+                colon = remainder.indexOf( ':' );
+                if ( colon >= 0 ){
+                    portList[i] = Integer.parseInt( remainder.substring( colon+1 ) );
+                } else {
+                    portList[i] = defaultPort;
+                }
             } else {
-                hostList[i] = s;
-                portList[i] = defaultPort;
+                colon = s.indexOf( ':' );
+                if ( colon > 0 ) {
+                    hostList[i] = s.substring( 0, colon );
+                    portList[i] = Integer.parseInt( s.substring( colon+1 ) );
+                } else {
+                    hostList[i] = s;
+                    portList[i] = defaultPort;
+                }
             }
             i++;
         }
 
         /* Create the Connection Setup Manager */
         m_connMgr = new LDAPConnSetupMgr(hostList, portList,
                                          m_isTLSFactory ? null : m_factory);
         m_connMgr.setConnSetupDelay(m_connSetupDelay);
--- a/java-sdk/ldapjdk/netscape/ldap/LDAPUrl.java
+++ b/java-sdk/ldapjdk/netscape/ldap/LDAPUrl.java
@@ -130,19 +130,21 @@ public class LDAPUrl implements java.io.
         parseUrl(url);
     }
 
     /**
      * Parse URL as defined in RFC 1959. Beyond the RFC, the secure ldap
      * (ldaps) is also supported.
      */
     private void parseUrl(String url) throws MalformedURLException {
-        StringTokenizer urlParser = new StringTokenizer (url, ":/?", true);
+        StringTokenizer urlParser = new StringTokenizer (url, ":/?[]", true);
+        StringTokenizer markParser = new StringTokenizer (url, ":/?[]", true);
         String currentToken;
         String str = null;
+        boolean usingIPv6 = false;
 
         try {
             currentToken = urlParser.nextToken();
             if (currentToken.equalsIgnoreCase ("LDAPS")) {
                 m_secure = true;
             }
             else if (!currentToken.equalsIgnoreCase ("LDAP")) {
                 throw new MalformedURLException ();
@@ -155,62 +157,76 @@ public class LDAPUrl implements java.io.
             currentToken = urlParser.nextToken();
             if (!currentToken.equals("/")) {
                 throw new MalformedURLException ();
             }
             currentToken = urlParser.nextToken();
             if (!currentToken.equals("/")) {
                 throw new MalformedURLException ();
             }
-        
             currentToken = urlParser.nextToken();
+            if (currentToken.equals("[")) {
+                usingIPv6 = true;
+            }
         }
         catch (NoSuchElementException e) {
             throw new MalformedURLException ();
         }
             
         // host-port
         if (currentToken.equals ("/")) {
             m_hostName = null;
             m_portNumber = m_secure ? DEFAULT_SECURE_PORT : LDAPv2.DEFAULT_PORT;
         } else if (currentToken.equals (":")) {
                 // port number without host name is not allowed
                throw new MalformedURLException ("No hostname");
         } else if (currentToken.equals ("?")) {
             throw new MalformedURLException ("No host[:port]");
+        } else if (usingIPv6){
+            StringBuilder sb = new StringBuilder();
+            while (urlParser.hasMoreElements()) {
+                currentToken = urlParser.nextToken();
+                if (currentToken.equals("]")) {
+                    break;
+                }
+                sb.append(currentToken);
+            }
+            m_hostName = sb.toString();
         } else {
             m_hostName = currentToken;
+        }
+        
+        // Set the port
+        if (urlParser.countTokens() == 0) {
+            m_portNumber = m_secure ? DEFAULT_SECURE_PORT : LDAPv2.DEFAULT_PORT;
+            return;
+        }
+        currentToken = urlParser.nextToken (); // either ":" or "/"
+
+        if (currentToken.equals (":")) {
+            try {
+                m_portNumber = Integer.parseInt (urlParser.nextToken());
+            } catch (NumberFormatException nf) {
+                throw new MalformedURLException ("Port not a number");
+            } catch (NoSuchElementException ex) {
+                throw new MalformedURLException ("No port number");
+            }
+                
             if (urlParser.countTokens() == 0) {
-                m_portNumber = m_secure ? DEFAULT_SECURE_PORT : LDAPv2.DEFAULT_PORT;
                 return;
             }
-            currentToken = urlParser.nextToken (); // either ":" or "/"
-
-            if (currentToken.equals (":")) {
-                try {
-                    m_portNumber = Integer.parseInt (urlParser.nextToken());
-                } catch (NumberFormatException nf) {
-                    throw new MalformedURLException ("Port not a number");
-                } catch (NoSuchElementException ex) {
-                    throw new MalformedURLException ("No port number");
-                }
-                    
-                if (urlParser.countTokens() == 0) {
-                    return;
-                }
-                else if (! urlParser.nextToken().equals("/")) {
-                   throw new MalformedURLException ();
-                }
-
-            } else if (currentToken.equals ("/")) {
-                m_portNumber = m_secure ? DEFAULT_SECURE_PORT : LDAPv2.DEFAULT_PORT;
-            } else {
-                // expecting ":" or "/"
+            else if (! urlParser.nextToken().equals("/")) {
                 throw new MalformedURLException ();
             }
+
+        } else if (currentToken.equals ("/")) {
+            m_portNumber = m_secure ? DEFAULT_SECURE_PORT : LDAPv2.DEFAULT_PORT;
+        } else {
+            // expecting ":" or "/"
+            throw new MalformedURLException ();
         }
 
 
         // DN
         if (!urlParser.hasMoreTokens ()) {
             return;
         }
         m_DN = decode(readNextConstruct(urlParser));