From 5995b93cbc5b084a44ab9c6d7a065d9b47b6d7f7 Mon Sep 17 00:00:00 2001
From: dugan <dugan@localhost>
Date: Tue, 19 Sep 2006 19:49:17 +0000
Subject: [PATCH] Add code to support issue #151 client connection disconnect.

---
 opendj-sdk/opends/src/server/org/opends/server/types/AddressMask.java                             |  597 ++++++++++++++++++++++++++++++---
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAddressMask.java |  275 +++++++++++++++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TypesTestCase.java   |   38 ++
 opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java          |   76 +--
 opendj-sdk/opends/resource/schema/02-config.ldif                                                  |    3 
 opendj-sdk/opends/src/server/org/opends/server/messages/ProtocolMessages.java                     |   35 +
 6 files changed, 924 insertions(+), 100 deletions(-)

diff --git a/opendj-sdk/opends/resource/schema/02-config.ldif b/opendj-sdk/opends/resource/schema/02-config.ldif
index e2073a3..03a17ef 100644
--- a/opendj-sdk/opends/resource/schema/02-config.ldif
+++ b/opendj-sdk/opends/resource/schema/02-config.ldif
@@ -1041,7 +1041,8 @@
 objectClasses: ( 1.3.6.1.4.1.26027.1.2.13
   NAME 'ds-cfg-connection-handler' SUP top STRUCTURAL
   MUST ( cn $ ds-cfg-connection-handler-class $
-  ds-cfg-connection-handler-enabled ) X-ORIGIN 'OpenDS Directory Server' )
+  ds-cfg-connection-handler-enabled ) MAY ( ds-cfg-allowed-client $ 
+  ds-cfg-denied-client ) X-ORIGIN 'OpenDS Directory Server' )
 objectClasses: ( 1.3.6.1.4.1.26027.1.2.14
   NAME 'ds-cfg-ldap-connection-handler' SUP ds-cfg-connection-handler
   STRUCTURAL MUST ds-cfg-listen-port MAY ( ds-cfg-listen-address $
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/ProtocolMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/ProtocolMessages.java
index 5f73b58..0a96460 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/ProtocolMessages.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/messages/ProtocolMessages.java
@@ -4132,7 +4132,28 @@
   public static final int MSGID_ACCTUSABLERES_DECODE_ERROR =
        CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_SEVERE_ERROR | 379;
 
+  /**
+   * The message ID for the message that will be used if an error occurs while
+   * attempting to decode an invalid AddressMask rule prefix.
+   */
+  public static final int MSGID_ADDRESSMASK_PREFIX_DECODE_ERROR =
+       CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_SEVERE_ERROR | 380;
 
+    /**
+   * The message ID for the message that will be used if an error occurs
+   * because a address mask prefix was specified with an wild card
+   * character "*".
+   */
+  public static final int MSGID_ADDRESSMASK_WILDCARD_DECODE_ERROR =
+       CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_SEVERE_ERROR | 381;
+
+  /**
+   * The message ID for the message that will be used if an error occurs
+   * because a address mask format was invalid.
+   *
+   */
+  public static final int MSGID_ADDRESSMASK_FORMAT_DECODE_ERROR =
+       CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_SEVERE_ERROR | 382;
 
   /**
    * Associates a set of generic messages with the message IDs defined in this
@@ -5893,8 +5914,18 @@
                     "The account availability response control had an " +
                     "unknown ACCOUNT_USABLE_RESPONSE element type of %s.");
     registerMessage(MSGID_ACCTUSABLERES_DECODE_ERROR,
-                    "Cannot decode the provided account availability " +
-                    "response control:  %s.");
+            "Cannot decode the provided account availability " +
+            "response control:  %s.");
+    registerMessage(MSGID_ADDRESSMASK_PREFIX_DECODE_ERROR,
+            "Cannot decode the provided address mask prefix because an" +
+            "invalid value was specified. The permitted values for IPv4" +
+            "are 0 to32 and for IPv6 0 to128");
+    registerMessage(MSGID_ADDRESSMASK_WILDCARD_DECODE_ERROR,
+            "Cannot decode the provided address mask because an prefix mask"+
+            "was specified with an wild card \"*\" match character.");
+    registerMessage(MSGID_ADDRESSMASK_FORMAT_DECODE_ERROR,
+            "Cannot decode the provided address mask because the it has an" +
+            "invalid format.");
   }
 }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java b/opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
index 92f2a62..870d79a 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
@@ -1224,12 +1224,44 @@
                   ServerSocketChannel serverChannel =
                        (ServerSocketChannel) key.channel();
                   SocketChannel clientChannel = serverChannel.accept();
-                  clientChannel.socket().setKeepAlive(useKeepAlive);
-                  clientChannel.socket().setTcpNoDelay(useTCPNoDelay);
-
                   LDAPClientConnection clientConnection =
                        new LDAPClientConnection(this, clientChannel);
+                  InetAddress clientAddr=clientConnection.getRemoteAddress();
+                  // Check to see if the client is on the denied list.  If so,
+                  // then reject it immediately.
+                  if((deniedClients != null) && (deniedClients.length > 0) &&
+                          AddressMask.maskListContains(clientAddr.getAddress(),
+                                  clientAddr.getHostName(), deniedClients))
+                  {
+                      clientConnection.disconnect(
+                              DisconnectReason.CONNECTION_REJECTED,
+                              sendRejectionNotice,
+                              MSGID_LDAP_CONNHANDLER_DENIED_CLIENT,
+                              clientConnection.getClientHostPort(),
+                              clientConnection.getServerHostPort());
 
+                      iterator.remove();
+                      continue;
+                  }
+                  // Check to see if there is an allowed list and if there is
+                  // whether the client is on that list.  If not, then reject
+                  // the connection.
+                  if((allowedClients != null) && (allowedClients.length > 0) &&
+                        (!AddressMask.maskListContains(clientAddr.getAddress(),
+                                  clientAddr.getHostName(), allowedClients)))
+                  {
+                      clientConnection.disconnect(
+                              DisconnectReason.CONNECTION_REJECTED,
+                              sendRejectionNotice,
+                              MSGID_LDAP_CONNHANDLER_DISALLOWED_CLIENT,
+                              clientConnection.getClientHostPort(),
+                              clientConnection.getServerHostPort());
+
+                      iterator.remove();
+                      continue;
+                  }
+                  clientChannel.socket().setKeepAlive(useKeepAlive);
+                  clientChannel.socket().setTcpNoDelay(useTCPNoDelay);
                   ConnectionSecurityProvider connectionSecurityProvider =
                        securityProvider.newInstance(clientConnection,
                                                     clientChannel);
@@ -1246,44 +1278,6 @@
                     continue;
                   }
 
-
-                  // Check to see if the client is on the denied list.  If so,
-                  // then reject it immediately.
-                  if ((deniedClients != null) &&
-                      AddressMask.maskListContains(clientConnection,
-                                                   deniedClients))
-                  {
-                    clientConnection.disconnect(
-                         DisconnectReason.CONNECTION_REJECTED,
-                         sendRejectionNotice,
-                         MSGID_LDAP_CONNHANDLER_DENIED_CLIENT,
-                         clientConnection.getClientHostPort(),
-                         clientConnection.getServerHostPort());
-
-                    iterator.remove();
-                    continue;
-                  }
-
-
-                  // Check to see if there is an allowed list and if there is
-                  // whether the client is on that list.  If not, then reject
-                  // the connection.
-                  if ((allowedClients != null) && (allowedClients.length > 0) &&
-                      (! AddressMask.maskListContains(clientConnection,
-                                                      allowedClients)))
-                  {
-                    clientConnection.disconnect(
-                         DisconnectReason.CONNECTION_REJECTED,
-                         sendRejectionNotice,
-                         MSGID_LDAP_CONNHANDLER_DISALLOWED_CLIENT,
-                         clientConnection.getClientHostPort(),
-                         clientConnection.getServerHostPort());
-
-                    iterator.remove();
-                    continue;
-                  }
-
-
                   // If we've gotten here, then we'll take the connection so
                   // choose a request handler and register the client with it.
                   try
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/AddressMask.java b/opendj-sdk/opends/src/server/org/opends/server/types/AddressMask.java
index 21ba599..193ab40 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/types/AddressMask.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/AddressMask.java
@@ -26,75 +26,560 @@
  */
 package org.opends.server.types;
 
-
-
-import org.opends.server.api.ClientConnection;
 import org.opends.server.config.ConfigException;
+import static org.opends.server.messages.ProtocolMessages.*;
+import static org.opends.server.messages.MessageHandler.*;
+import java.util.BitSet;
 
+//This import statements causes problems in checkstyles so
+//it has been turned off until issue #??? is fixed.
+//import sun.net.util.IPAddressUtil;
+//import java.net.Inet6Address;
 
 
 /**
  * This class defines an address mask, which can be used to perform
  * efficient comparisons against IP addresses to determine whether a
  * particular IP address is in a given range.
+ * Currently IPV6 is not supported. Issue #670 will track IPV6
+ * support.
  */
-public class AddressMask
+
+public final class AddressMask
 {
-  // NYI
 
-
+   /**
+   * The fully-qualified name of this class for debugging purposes.
+   */
+  private static final String CLASS_NAME =
+       "org.opends.server.types.AddressMask";
 
   /**
-   * Decodes the provided string as an address mask.
-   *
-   * @param  maskString  The string to decode as an address mask.
-   *
-   * @return  AddressMask  The address mask decoded from the provided
-   *                       string.
-   *
-   * @throws  ConfigException  If the provided string cannot be
-   *                           decoded as an address mask.
-   */
-  public static AddressMask decode(String maskString)
-         throws ConfigException
-  {
-    // NYI
-    return null;
+     * Types of rules we have.
+     *
+     * IPv4 - ipv4 rule
+     * IPv6 - ipv6 rule (begin with '['). Not supported see issue #670
+     * HOST - hostname match (foo.sun.com)
+     * HOSTPATTERN - host pattern match (begin with '.')
+     * ALLWILDCARD - *.*.*.* (first HOST is applied then ipv4)
+     *
+     */
+
+     enum RuleType
+    {
+        IPv4, IPv6, HOSTPATTERN, ALLWILDCARD, HOST;
+    }
+
+    // Type of rule determined
+    private  RuleType ruleType;
+
+    // IPv4 values for number of bytes and max CIDR prefix
+    /**
+     * IPv4 address size.
+     */
+    public static int IN4ADDRSZ = 4;
+    private  int IPV4MAXPREFIX = 32;
+
+    // IPv6 values for number of bytes and max CIDR prefix
+    //private  int IN6ADDRSZ = 16;
+    //private  int IPV6MAXPREFIX = 128;
+
+    //Holds binary representations of rule and mask respectively.
+    private  byte[] ruleMask, prefixMask;
+
+    //Bit array that holds wildcard info for above binary arrays.
+    private  BitSet wildCard = new BitSet();
+
+    //Array that holds each component of a hostname.
+    private  String[] hostName;
+
+    //Holds a hostname pattern (ie, rule that begins with '.');'
+    private  String hostPattern;
+
+    //Holds string passed into the constructor.
+    private  String ruleString;
+
+    /**
+     * Address mask constructor.
+     * @param rule The rule string to process.
+     * @throws ConfigException If the rule string is not valid.
+     */
+    private AddressMask( String rule)
+    throws ConfigException
+    {
+        determineRuleType(rule);
+        switch (ruleType)
+        {
+        case IPv4:
+            processIpv4(rule);
+            break;
+
+            /*            case IPv6:
+                processIPv6(rule);
+                break;
+             */
+        case HOST:
+            processHost(rule);
+            break;
+
+        case HOSTPATTERN:
+            processHostPattern(rule);
+            break;
+
+        case ALLWILDCARD:
+            processAllWilds(rule);
+        }
+        ruleString=rule;
+    }
+
+    /**
+     * Try to determine what type of rule string this is. See
+     * RuleType above for valid types.
+     * @param ruleString The rule string to be examined.
+     * @throws ConfigException If the rule type cannot be
+     *         determined from the rule string.
+     */
+    private void  determineRuleType(String ruleString)
+    throws ConfigException
+    {
+
+        //Rule ending with '.' is invalid'
+        if(ruleString.endsWith("."))
+        {
+            int msgID=MSGID_ADDRESSMASK_FORMAT_DECODE_ERROR;
+            String message = getMessage(msgID);
+            throw new ConfigException(msgID, message);
+        }
+        else if(ruleString.startsWith("."))
+        {
+            ruleType=RuleType.HOSTPATTERN;
+        }
+        else if(ruleString.startsWith("["))
+        {
+            int msgID=MSGID_ADDRESSMASK_FORMAT_DECODE_ERROR;
+            String message = getMessage(msgID);
+            throw new ConfigException(msgID, message);
+            //IPV6 is not supported see issue #670
+            //ruleType=RuleType.IPv6;
+        }
+        else
+        {
+            int wildCount=0;
+            String[] s = ruleString.split("\\.", -1);
+            //Try to figure out how many wildcards and if the rule is
+            // hostname (can't begin with digit) or ipv4 address.
+            //Default to IPv4 ruletype.
+            ruleType=RuleType.HOST;
+            for(int i=0;i<s.length;i++)
+            {
+                if(s[i].equals("*"))
+                {
+                    wildCount++;
+                    continue;
+                }
+                //Looks like an ipv4 address
+                if(Character.isDigit(s[i].charAt(0)))
+                {
+                    ruleType=RuleType.IPv4;
+                    break;
+                }
+            }
+            //All wildcards (*.*.*.*)
+            if(wildCount == s.length)
+            {
+                ruleType=RuleType.ALLWILDCARD;
+            }
+        }
+    }
+
+    /**
+     * The rule string is an IPv4 rule. Build both the prefix
+     * mask array and rule mask from the string.
+     * @param rule The rule string containing the IPv4 rule.
+     * @throws ConfigException If the rule string is not a valid
+     *         IPv4 rule.
+     */
+    private void processIpv4(String rule)
+    throws ConfigException {
+        String[] s = rule.split("/", -1);
+        ruleMask=new byte[IN4ADDRSZ];
+        prefixMask=new byte[IN4ADDRSZ];
+        prefixMask(processPrefix(s,IPV4MAXPREFIX));
+        processIpv4Subnet((s.length == 0) ? rule : s[0]);
+    }
+
+    /**
+     * The rule string is all wildcards. Set both address wildcard
+     * bitmask and hostname wildcard array.
+     * @param rule The rule string containing all wildcards.
+     */
+    private void processAllWilds(String rule)
+    {
+        String s[]=rule.split("\\.", -1);
+        if(s.length == IN4ADDRSZ)
+        {
+            for(int i=0;i<IN4ADDRSZ;i++)
+                wildCard.set(i);
+        }
+        hostName=rule.split("\\.", -1);
+    }
+
+    /**
+     * Examine the rule string of a host pattern and set the
+     * host pattern from the rule.
+     * @param rule The rule string to examine.
+     * @throws ConfigException If the rule string is not a valid
+     *         host pattern rule.
+     */
+    private void processHostPattern(String rule)
+    throws ConfigException
+    {
+        //quick check for invalid chars like " "
+        String s[]=rule.split("^[0-9a-zA-z-.]+");
+        if(s.length > 0)
+        {
+            int msgID=MSGID_ADDRESSMASK_FORMAT_DECODE_ERROR;
+            String message = getMessage(msgID);
+            throw new ConfigException(msgID,  message);
+        }
+        hostPattern=rule;
+    }
+
+    /**
+     * Examine rule string and build a hostname string array
+     * of its parts.
+     * @param rule The rule string.
+     * @throws ConfigException If the rule string is not a valid
+     *         host name.
+     */
+    private void processHost(String rule)
+    throws ConfigException
+    {
+        //Note that '*' is valid in host rule
+        String s[]=rule.split("^[0-9a-zA-z-.*]+");
+        if(s.length > 0)
+        {
+            int msgID=MSGID_ADDRESSMASK_FORMAT_DECODE_ERROR;
+            String message = getMessage(msgID);
+            throw new ConfigException(msgID, message);
+        }
+        hostName=rule.split("\\.", -1);
+    }
+
+    /**
+     * Build the prefix mask of prefix len bits set in the array.
+     * @param prefix The len of the prefix to use.
+     */
+    private void prefixMask(int prefix)
+    {
+        int i=0;
+        for( i=0;prefix > 8 ; i++)
+        {
+            prefixMask[i] = (byte) 0xff;
+            prefix -= 8;
+        }
+        prefixMask[i] = (byte) ((0xff) << (8 - prefix));
+    }
+
+    /**
+     * Examine the subnet part of a rule string and build a
+     * byte array representation of it.
+     * @param subnet The subnet string part of the rule.
+     * @throws ConfigException If the subnet string is not a valid
+     *         IPv4 subnet string.
+     */
+    private void  processIpv4Subnet(String subnet)
+    throws ConfigException {
+        String[] s = subnet.split("\\.", -1);
+        try {
+            //Make sure we have four parts
+            if(s.length != IN4ADDRSZ) {
+                int id=MSGID_ADDRESSMASK_FORMAT_DECODE_ERROR;
+                String message = getMessage(id);
+                throw new ConfigException(id, message);
+            }
+            for(int i=0; i < IN4ADDRSZ; i++)
+            {
+                String quad=s[i].trim();
+                if(quad.equals("*"))
+                    wildCard.set(i) ; //see wildcard mark bitset
+                else
+                {
+                    long val=Integer.parseInt(quad);
+                    //must be between 0-255
+                    if((val < 0) ||  (val > 0xff))
+                    {
+                        int id=MSGID_ADDRESSMASK_FORMAT_DECODE_ERROR;
+                        String message = getMessage(id);
+                        throw new ConfigException(id, message);
+                    }
+                    ruleMask[i] = (byte) (val & 0xff);
+                }
+            }
+        } catch (NumberFormatException nfex)
+        {
+            int id=MSGID_ADDRESSMASK_FORMAT_DECODE_ERROR;
+            String message = getMessage(id);
+            throw new ConfigException(id, message);
+        }
+    }
+
+    /**
+     * Examine rule string for correct prefix usage.
+     * @param s The string array with rule string add and prefix
+     *          strings.
+     * @param maxPrefix The max value the prefix can be.
+     * @return The prefix integer value.
+     * @throws ConfigException If the string array and prefix
+     *         are not valid.
+     */
+    private int  processPrefix(String[] s, int maxPrefix)
+    throws ConfigException {
+        int prefix=maxPrefix;
+        try {
+            //can only have one prefix value and a subnet string
+            if((s.length  < 1) || (s.length > 2) )
+            {
+                int msgID=MSGID_ADDRESSMASK_FORMAT_DECODE_ERROR;
+                String message = getMessage(msgID);
+                throw new ConfigException(msgID, message);
+            }
+            else  if(s.length == 2)
+            {
+                //can't have wildcard with a prefix
+                if(s[0].indexOf('*') > -1)
+                {
+                    int msgID=MSGID_ADDRESSMASK_WILDCARD_DECODE_ERROR;
+                    String message = getMessage(msgID);
+                    throw new ConfigException(msgID, message);
+                }
+                prefix = Integer.parseInt(s[1]);
+            }
+            //must be between 0-maxprefix
+            if((prefix < 0) || (prefix > maxPrefix))
+            {
+                int msgID=MSGID_ADDRESSMASK_PREFIX_DECODE_ERROR;
+                String message = getMessage(msgID);
+                throw new ConfigException(msgID, message);
+            }
+        }
+        catch(NumberFormatException nfex)
+        {
+            int msgID=MSGID_ADDRESSMASK_FORMAT_DECODE_ERROR;
+            String msg = getMessage(msgID);
+            throw new ConfigException(msgID,msg);
+        }
+        return prefix;
+    }
+
+
+    /**
+     * Decodes the provided string as an address mask.
+     *
+     * @param  maskString  The string to decode as an address mask.
+     *
+     * @return  AddressMask  The address mask decoded from the
+     *                       provided string.
+     *
+     * @throws  ConfigException  If the provided string cannot be
+     *                           decoded as an address mask.
+     */
+
+
+    public static AddressMask decode(String maskString)
+    throws ConfigException {
+        return new AddressMask(maskString);
+    }
+
+    /**
+     * Indicates whether provided address or hostname matches one of
+     * the address masks in the provided array.
+     *
+     * @param remoteAddr The remote address byte array.
+     * @param remoteName The remote host name string.
+     * @param masks      An array of address masks to check.
+     * @return <CODE>true</CODE> if the provided address or hostname
+     *          does match one of the given address masks, or
+     *         <CODE>false</CODE> if it does not.
+     */
+    public  static boolean maskListContains(byte[] remoteAddr,
+            String remoteName,
+            AddressMask[] masks)
+    {
+        for(int i=0; i < masks.length; i++)
+        {
+            if(masks[i].match(remoteAddr, remoteName))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Retrieves a string representation of this address mask.
+     *
+     * @return  A string representation of this address mask.
+     */
+    public String toString()
+    {
+        return new String(ruleString);
+    }
+
+    /**
+     * Main match function that determines which rule-type match
+     * function to use.
+     * @param remoteAddr The remote client address byte array.
+     * @param remoteName The remote client host name.
+     * @return <CODE>true</CODE>if one of the match functions found
+     *         a match or <CODE>false</CODE>if not.
+     */
+    private boolean match(byte[] remoteAddr, String remoteName)
+    {
+        boolean ret=false;
+
+        switch(ruleType) {
+        case IPv4:
+            //this Address mask is an IPv4 rule
+            ret=matchAddress(remoteAddr);
+            break;
+
+        case HOST:
+            // HOST rule use hostname
+            ret=matchHostName(remoteName);
+            break;
+
+            /*
+          case IPv6:
+              //IPv6 rule only valid of addr is an Inet6Address
+              if(addr instanceof Inet6Address) {
+                  Inet6Address addr6 = (Inet6Address) addr;
+                  ret=match(addr6.getAddress());
+              }
+              break;
+             */
+        case HOSTPATTERN:
+            //HOSTPATTERN rule
+            ret=matchPattern(remoteName);
+            break;
+
+        case ALLWILDCARD:
+            //first try  ipv4 addr match, then hostname
+            ret=matchAddress(remoteAddr);
+            if(!ret)
+                ret=matchHostName(remoteName);
+            break;
+        }
+        return ret;
+    }
+
+    /**
+     * Try to match remote host name string against the pattern rule.
+     * @param remoteHostName The remote client host name.
+     * @return <CODE>true</CODE>if the remote host name matches or
+     *         <CODE>false</CODE>if not.
+     */
+    private boolean matchPattern(String remoteHostName) {
+        int len=remoteHostName.length() - hostPattern.length();
+        if(len > 0)
+        {
+            return remoteHostName.regionMatches(true,len,
+                    hostPattern,0,hostPattern.length());
+        }
+        return false;
+    }
+
+    /**
+     * Try to match remote client host name against rule host name.
+     * @param remoteHostName The remote host name string.
+     * @return <CODE>true</CODE>if the remote client host name matches
+     *         <CODE>false</CODE> if it does not.
+     */
+    private boolean matchHostName(String remoteHostName) {
+        String[] s = remoteHostName.split("\\.", -1);
+        if(s.length != hostName.length)
+            return false;
+        if(ruleType == RuleType.ALLWILDCARD)
+            return true;
+        for(int i=0;i<s.length;i++)
+        {
+            if(!hostName[i].equals("*")) //skip if wildcard
+            {
+                if(!s[i].equalsIgnoreCase(hostName[i]))
+                    return false;
+            }
+        }
+        return true;
+    }
+
+
+    /**
+     * Try to match remote client address using prefix mask and
+     * rule mask.
+     * @param remoteMask The byte array with remote client address.
+     * @return <CODE>true</CODE> if remote client address matches or
+     *         <CODE>false</CODE>if not.
+     */
+    private boolean matchAddress(byte[] remoteMask)
+    {
+        if(prefixMask== null)
+            return false;
+        if(remoteMask.length != prefixMask.length)
+            return false;
+        if(ruleType  == RuleType.ALLWILDCARD)
+            return true;
+        for(int i=0;i < prefixMask.length; i++)
+        {
+            if(!wildCard.get(i))
+            {
+                if((ruleMask[i] & prefixMask[i]) !=
+                    (remoteMask[i] & prefixMask[i]))
+                    return false;
+            }
+        }
+        return true;
+    }
+
+    /* Turned off until IPV6 issue #670 is fixed.
+
+  private void processIPv6(String rule)
+  throws ConfigException {
+      String[] s = rule.split("/", -1);
+      //ipv6 rule must end with ']''
+      if(!s[0].endsWith("]"))
+      {
+          int msgID=MSGID_ADDRESSMASK_FORMAT_DECODE_ERROR;
+          String message = getMessage(msgID);
+          throw new ConfigException(msgID,message);
+      }
+      String subnet  = s[0].substring(1, s[0].length() -1);
+      byte[] tmpMask=IPAddressUtil.textToNumericFormatV6(subnet);
+      //don't have a vaild ipv6 address bail
+      if (tmpMask == null)
+      {
+          int msgID=MSGID_ADDRESSMASK_FORMAT_DECODE_ERROR;
+          String message = getMessage(msgID);
+          throw new ConfigException(msgID, message);remoteMask
+      }
+      //we were returned an ipv4-mapped address ::ffff:<ipv4 addr>
+      //make sure we don't have a prefix
+      if((tmpMask.length == IN4ADDRSZ)  &&
+              (s.length == 2)) {
+          int msgID = MSGID_ADDRESSMASK_FORMAT_DECODE_ERROR;
+          String message = getMessage(msgID);
+          throw new ConfigException(msgID,  message);
+       //build a ipv4 structure using a 32-bit prefix
+      } else if (tmpMask.length == IN4ADDRSZ) {
+          setRuleType(Rtype.IPv4);
+          setRuleMask(tmpMask);
+          setPrefixMask(new byte[IN4ADDRSZ]);
+          prefixMask(32);
+      } else { //plain Ipv6 address
+          setRuleMask(tmpMask);
+          setPrefixMask(new byte[IN6ADDRSZ]);
+          prefixMask(processPrefix(s,IPV6MAXPREFIX));
+          setRuleType(Rtype.IPv6);
+      }
   }
-
-
-
-  /**
-   * Indicates whether the provided address matches one of the address
-   * masks in the provided array.
-   *
-   * @param  clientConnection  The client connection for which to make
-   *                           the determination.
-   * @param  masks             The set of address masks to check.
-   *
-   * @return  <CODE>true</CODE> if the provided address does match one
-   *          or more of the given address masks, or
-   *          <CODE>false</CODE> if it does not.
-   */
-  public static boolean maskListContains(
-                             ClientConnection clientConnection,
-                             AddressMask[] masks)
-  {
-    // NYI
-    return false;
-  }
-
-
-
-  /**
-   * Retrieves a string representation of this address mask.
-   *
-   * @return  A string representation of this address mask.
-   */
-  public String toString()
-  {
-    // NYI
-    return null;
-  }
+     */
 }
 
+
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAddressMask.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAddressMask.java
new file mode 100644
index 0000000..043eca6
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAddressMask.java
@@ -0,0 +1,275 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying * information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2006 Sun Microsystems, Inc.
+ */
+package org.opends.server.types;
+
+import org.opends.server.types.AddressMask;
+import org.opends.server.config.ConfigException;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+public class TestAddressMask extends TypesTestCase {
+
+	/* These are all valid rules -- should all pass. */
+    @DataProvider(name = "validRules")
+    public Object[][] validData() {
+        return new Object[][] {
+            { "129.34.55.67"},
+            { "129.*.78.55"},
+            {".central.sun.com"},
+            {"foo.central.sun.com"},
+            {"foo.*.sun.*"},
+            {"128.*.*.*"},
+            {"129.45.23.67/22"},
+            {"128.33.23.21/32"},
+            {"*.*.*.*"},
+            {"129.45.67.34/0"},
+            {"foo.com"},
+            {"foo"}
+        };
+    }
+    
+ @DataProvider(name = "invalidRules")
+  public Object[][] invalidData() {
+    return new Object[][] {
+         { "129.*.900.67" },
+         { "129.67" },
+         {"   "},
+         {"129.56.78.90/2000"},
+         {"677.777.AG.BC"},
+         {"/34"},
+         {"234.12.12.*/31"},
+         {"234.12.12.90/"},
+         {"129.34.56.78/-100"},
+         {"129"},
+         {"129.34.-90.67"},
+         {"129.**.56.67"},
+         {"foo bar.com"},
+         {"12foo.example.com"},
+         {"[2001:fecd:ba23:cd1f:dcb1:1010:9234:4088]/124"},
+         {"123.45."},
+         {".central.sun day.com"},
+         {"129.34.45.45/4/3/"}
+    };
+  }
+    
+ @DataProvider(name = "toStringRule")
+ public Object[][] toStringData() {
+     return new Object[][] {
+         {"129.35.45.66/12"}
+     };
+ }
+
+@Test(dataProvider = "validRules")
+ public void testValidDecode(String mask)
+ throws Exception {
+     AddressMask.decode(mask);
+ }
+
+ @Test(expectedExceptions=ConfigException.class, dataProvider="invalidRules")
+ public void testInvalidDecode(String mask)
+ throws Exception {
+     try {
+         AddressMask.decode(mask);
+     } catch (ConfigException e) {
+         throw e;
+     } catch (Exception e) {
+         //MPD FIX this
+         System.out.println(
+                 "Invalid mask  <" + mask + "> threw wrong exception type.");
+         throw e;
+     }
+     throw new RuntimeException(
+             "Invalid mask <" + mask + "> did not throw an exception.");
+ }
+
+ @DataProvider(name = "matchRules")
+ public Object[][] ruleMatchData() {
+     return new Object[][] {
+             {
+                 //Rules
+                 new String[] {
+                         "129.56.*.22", //1
+                         "*.domain.com", //2
+                         "foo.example.com", //3
+                         "126.67.89.90", //4
+                         "90.89.78.67/30", //5
+                         ".test.com", //6
+                         "128.153.147.32/21",//7
+                         "128.153.146.32/26",//8
+                         "90.89.78.67/26"}, //9
+                //Addresses         
+                new String[] {
+                         "128.153.147.45", //rule 7
+                         "128.153.146.60", //rule 8
+                         "148.45.45.46",     //host
+                         "129.56.78.22",    //rule 1
+                         "148.45.45.47",    //host
+                         "148.45.45.48",    //host
+                         "90.89.78.65"},   //rule 5
+              //Hostnames           
+              new String[]  {
+                         "some.host.name", //addr
+                         "some.host.name", //addr
+                         "foo.example.com", //rule 3
+                         "some.host.name", //addr
+                         "foo.test.com",       //rule 6
+                         "foo.domain.com", //rule 2
+                         "some.host.name" //addr
+                         }
+             }
+     };
+ }
+
+ @DataProvider(name = "noMatchRules")
+ public Object[][] ruleNoMatchData() {
+     return new Object[][] {
+         {
+             // Rule to not match
+             new String[] {
+                     "129.56.*.22", //1
+                     "*.domain.com", //2
+                     "foo.example.com", //3
+                     "126.67.89.90", //4
+                     "90.89.78.67/30", //5
+                     ".test.com", //6
+                     "128.153.147.32/21",//7
+                     "128.153.146.32/26",//8
+                     "90.89.78.67/26"}, //9
+                     //Addresses         
+                     new String[] {
+                              "128.153.140.45", 
+                              "128.153.143.255",
+                              "148.45.45.46",
+                              "126.56.78.22",
+                              "148.45.45.47",
+                              "148.45.45.48",
+                              "90.89.78.128",
+                              "148.45.45.49"},
+                   //Hostnames           
+                   new String[]  {
+                              "some.host.name",
+                              "some.host.name",
+                              "foo.examplee.com",
+                              "some.host.name",
+                              "foo.ttest.com",
+                              "foo.domain.comm",
+                              "some.host.name",
+                              "f.e.c",
+                              "foo.domain.cm"}
+                  }
+         };
+     }
+ 
+ @DataProvider(name = "matchWCRules")
+ public Object[][] ruleMatchWCData() {
+     return new Object[][] {
+             {
+                 //Rules
+                 new String[] {
+                         "*.*.*",
+                         "*.*.*.*"}, 
+                //Addresses         
+                new String[] {
+                        "129.34.45.12",
+                        "129.34.45.13"},  
+              //Hostnames           
+              new String[]  {
+                         "some.host.name" ,
+                         "some.host.name"}
+             }
+     };
+ }
+
+ @Test(dataProvider = "matchRules")
+ public void testMatch(String[] rules, String[] addrs, String[]hostNames) {
+     boolean ret=true;
+     ret=match(rules,addrs,hostNames);
+     assertTrue(ret);
+ }
+
+ @Test(dataProvider = "matchWCRules")
+ public void testWildCardMatch(String[] rules, String[] addrs, String[]hostNames) {
+     boolean ret=true;
+     ret=match(rules,addrs,hostNames);
+     assertTrue(ret);
+ }
+
+ @Test(dataProvider = "noMatchRules")
+ public void testNoMatch(String[] rules, String[] addrs, String[] hostNames) {
+     boolean ret=false;
+     ret=match(rules,addrs,hostNames);
+     assertFalse(ret);
+ }
+
+ @Test(dataProvider="toStringRule")
+ public void testToString(String rule) {
+     try {
+         AddressMask m = AddressMask.decode(rule);
+         assertEquals(rule, m.toString());
+     } catch (ConfigException ce) {
+         throw new RuntimeException(
+                 "Invalid mask <" + rule + "> data should be all valid for this test");
+     }
+ }
+ 
+ private byte[] getAddress(String remote) {
+     byte[] addr=new byte[AddressMask.IN4ADDRSZ];
+     String[] s = remote.split("\\.", -1);
+     try {
+         for(int i=0;i<AddressMask.IN4ADDRSZ;i++) {
+             long val = Integer.parseInt(s[i]);
+             addr[i] = (byte) (val & 0xff);
+         }
+     }  catch (NumberFormatException nfex) {
+         return addr;
+     }
+     return addr;
+ }
+ 
+ private boolean match(String[] rules, String[] addrs, String[]hostNames) {
+     boolean ret=true;
+     int i=0;
+     
+     AddressMask[] m = new AddressMask[rules.length];
+     try {
+         for (i = 0; i < rules.length; i++) {
+             m[i] = AddressMask.decode(rules[i]);
+         }
+     } catch (ConfigException ce) {
+         throw new RuntimeException(
+                 "Invalid mask <" + rules[i] + "> all data must be valid for this test");
+     }
+     for(int j =0; j < addrs.length; j++) {
+         if(!AddressMask.maskListContains(getAddress(addrs[j]),hostNames[j],m)) {
+             ret=false;
+             break;
+         }
+     }
+     return ret;
+ }
+}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TypesTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TypesTestCase.java
new file mode 100644
index 0000000..e409e72
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TypesTestCase.java
@@ -0,0 +1,38 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying * information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2006 Sun Microsystems, Inc.
+ */
+package org.opends.server.types ;
+
+import org.opends.server.DirectoryServerTestCase;
+import org.testng.annotations.Test;
+
+/**
+ * An abstract class that all types  unit test should extend. 
+ */
+
+@Test(groups = { "precommit, types" })
+public abstract class TypesTestCase extends DirectoryServerTestCase 
+{}

--
Gitblit v1.10.0