| | |
| | | * Portions copyright 2011-2013 ForgeRock AS |
| | | */ |
| | | package org.opends.server.types; |
| | | import org.opends.messages.Message; |
| | | |
| | | import org.opends.server.config.ConfigException; |
| | | |
| | | |
| | | import static org.opends.messages.ProtocolMessages.*; |
| | | import java.util.BitSet; |
| | | import java.util.Collection; |
| | | |
| | | import java.net.Inet6Address; |
| | | import java.net.InetAddress; |
| | | import java.net.UnknownHostException; |
| | | import java.util.BitSet; |
| | | import java.util.Collection; |
| | | |
| | | import org.opends.messages.Message; |
| | | import org.opends.server.config.ConfigException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * 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. |
| | | * 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. |
| | | */ |
| | | @org.opends.server.types.PublicAPI( |
| | | stability=org.opends.server.types.StabilityLevel.VOLATILE, |
| | | mayInstantiate=true, |
| | | mayExtend=false, |
| | | mayInvoke=true) |
| | | stability = org.opends.server.types.StabilityLevel.VOLATILE, |
| | | mayInstantiate = true, mayExtend = false, mayInvoke = true) |
| | | public final class AddressMask |
| | | { |
| | | /** |
| | | * Types of rules we have. |
| | | * |
| | | * IPv4 - ipv4 rule |
| | | * IPv6 - ipv6 rule (begin with '[' or contains an ':'). |
| | | * HOST - hostname match (foo.sun.com) |
| | | * HOSTPATTERN - host pattern match (begin with '.') |
| | | * ALLWILDCARD - *.*.*.* (first HOST is applied then ipv4) |
| | | * |
| | | */ |
| | | * Types of rules we have. IPv4 - ipv4 rule IPv6 - ipv6 rule (begin with '[' |
| | | * or contains an ':'). HOST - hostname match (foo.sun.com) HOSTPATTERN - host |
| | | * pattern match (begin with '.') ALLWILDCARD - *.*.*.* (first HOST is applied |
| | | * then ipv4) |
| | | */ |
| | | enum RuleType |
| | | { |
| | | ALLWILDCARD, HOST, HOSTPATTERN, IPv4, IPv6 |
| | | } |
| | | |
| | | enum RuleType |
| | | |
| | | |
| | | // IPv4 values for number of bytes and max CIDR prefix |
| | | private static final int IN4ADDRSZ = 4; |
| | | private static final int IPV4MAXPREFIX = 32; |
| | | |
| | | // IPv6 values for number of bytes and max CIDR prefix |
| | | private static final int IN6ADDRSZ = 16; |
| | | private static final int IPV6MAXPREFIX = 128; |
| | | |
| | | |
| | | |
| | | /** |
| | | * 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(final String maskString) |
| | | throws ConfigException |
| | | { |
| | | return new AddressMask(maskString); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Indicates whether provided address matches one of the address masks in the |
| | | * provided collection. |
| | | * |
| | | * @param address |
| | | * The address to check. |
| | | * @param masks |
| | | * A collection of address masks to check. |
| | | * @return <CODE>true</CODE> if the provided address matches one of the given |
| | | * address masks, or <CODE>false</CODE> if it does not. |
| | | */ |
| | | public static boolean maskListContains(final InetAddress address, |
| | | final Collection<AddressMask> masks) |
| | | { |
| | | for (final AddressMask mask : masks) |
| | | { |
| | | IPv4, IPv6, HOSTPATTERN, ALLWILDCARD, HOST |
| | | if (mask.match(address)) |
| | | { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | // Type of rule determined |
| | | private RuleType ruleType; |
| | | |
| | | // IPv4 values for number of bytes and max CIDR prefix |
| | | /** |
| | | * IPv4 address size. |
| | | */ |
| | | private static final int IN4ADDRSZ = 4; |
| | | private static final int IPV4MAXPREFIX = 32; |
| | | |
| | | // IPv6 values for number of bytes and max CIDR prefix |
| | | private static final int IN6ADDRSZ = 16; |
| | | private static final int IPV6MAXPREFIX = 128; |
| | | // Array that holds each component of a hostname. |
| | | private String[] hostName; |
| | | |
| | | //Holds binary representations of rule and mask respectively. |
| | | private byte[] ruleMask, prefixMask; |
| | | // Holds a hostname pattern (ie, rule that begins with '.');' |
| | | private String hostPattern; |
| | | |
| | | //Bit array that holds wildcard info for above binary arrays. |
| | | private final BitSet wildCard = new BitSet(); |
| | | // Holds binary representations of rule and mask respectively. |
| | | private byte[] ruleMask, prefixMask; |
| | | |
| | | //Array that holds each component of a hostname. |
| | | private String[] hostName; |
| | | // Holds string passed into the constructor. |
| | | private final String ruleString; |
| | | |
| | | //Holds a hostname pattern (ie, rule that begins with '.');' |
| | | private String hostPattern; |
| | | // Type of rule determined |
| | | private RuleType ruleType; |
| | | |
| | | //Holds string passed into the constructor. |
| | | private String ruleString; |
| | | // Bit array that holds wildcard info for above binary arrays. |
| | | private final BitSet wildCard = new BitSet(); |
| | | |
| | | /** |
| | | * 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 |
| | | |
| | | |
| | | /** |
| | | * Address mask constructor. |
| | | * |
| | | * @param rule |
| | | * The rule string to process. |
| | | * @throws ConfigException |
| | | * If the rule string is not valid. |
| | | */ |
| | | private AddressMask(final String rule) throws ConfigException |
| | | { |
| | | determineRuleType(rule); |
| | | switch (ruleType) |
| | | { |
| | | determineRuleType(rule); |
| | | switch (ruleType) |
| | | { |
| | | case IPv6: |
| | | processIPv6(rule); |
| | | break; |
| | | case IPv6: |
| | | processIPv6(rule); |
| | | break; |
| | | |
| | | case IPv4: |
| | | processIpv4(rule); |
| | | break; |
| | | case IPv4: |
| | | processIpv4(rule); |
| | | break; |
| | | |
| | | case HOST: |
| | | processHost(rule); |
| | | break; |
| | | case HOST: |
| | | processHost(rule); |
| | | break; |
| | | |
| | | case HOSTPATTERN: |
| | | processHostPattern(rule); |
| | | break; |
| | | case HOSTPATTERN: |
| | | processHostPattern(rule); |
| | | break; |
| | | |
| | | case ALLWILDCARD: |
| | | processAllWilds(rule); |
| | | } |
| | | ruleString=rule; |
| | | 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 |
| | | |
| | | |
| | | /** |
| | | * Retrieves a string representation of this address mask. |
| | | * |
| | | * @return A string representation of this address mask. |
| | | */ |
| | | @Override |
| | | public String toString() |
| | | { |
| | | return ruleString; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 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(final String ruleString) |
| | | throws ConfigException |
| | | { |
| | | |
| | | // Rule ending with '.' is invalid' |
| | | if (ruleString.endsWith(".")) |
| | | { |
| | | final Message message = ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | } |
| | | else if (ruleString.startsWith(".")) |
| | | { |
| | | ruleType = RuleType.HOSTPATTERN; |
| | | } |
| | | else if (ruleString.startsWith("[") || (ruleString.indexOf(':') != -1)) |
| | | { |
| | | ruleType = RuleType.IPv6; |
| | | } |
| | | else |
| | | { |
| | | int wildCount = 0; |
| | | final 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 (final String value : s) |
| | | { |
| | | if (value.equals("*")) |
| | | { |
| | | wildCount++; |
| | | continue; |
| | | } |
| | | // Looks like an ipv4 address |
| | | if (Character.isDigit(value.charAt(0))) |
| | | { |
| | | ruleType = RuleType.IPv4; |
| | | break; |
| | | } |
| | | } |
| | | // All wildcards (*.*.*.*) |
| | | if (wildCount == s.length) |
| | | { |
| | | ruleType = RuleType.ALLWILDCARD; |
| | | } |
| | | } |
| | | } |
| | | |
| | | //Rule ending with '.' is invalid' |
| | | if(ruleString.endsWith(".")) |
| | | |
| | | |
| | | /** |
| | | * Main match function that determines which rule-type match function to use. |
| | | * |
| | | * @param address |
| | | * The address to check. |
| | | * @return <CODE>true</CODE>if one of the match functions found a match or |
| | | * <CODE>false</CODE>if not. |
| | | */ |
| | | private boolean match(final InetAddress address) |
| | | { |
| | | boolean ret = false; |
| | | |
| | | switch (ruleType) |
| | | { |
| | | case IPv6: |
| | | case IPv4: |
| | | // this Address mask is an IPv4 rule |
| | | ret = matchAddress(address.getAddress()); |
| | | break; |
| | | |
| | | case HOST: |
| | | // HOST rule use hostname |
| | | ret = matchHostName(address.getHostName()); |
| | | break; |
| | | |
| | | case HOSTPATTERN: |
| | | // HOSTPATTERN rule |
| | | ret = matchPattern(address.getHostName()); |
| | | break; |
| | | |
| | | case ALLWILDCARD: |
| | | // first try ipv4 addr match, then hostname |
| | | ret = matchAddress(address.getAddress()); |
| | | if (!ret) |
| | | { |
| | | ret = matchHostName(address.getHostName()); |
| | | } |
| | | break; |
| | | } |
| | | return ret; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 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(final byte[] remoteMask) |
| | | { |
| | | if (ruleType == RuleType.ALLWILDCARD) |
| | | { |
| | | return true; |
| | | } |
| | | if (prefixMask == null) |
| | | { |
| | | return false; |
| | | } |
| | | if (remoteMask.length != prefixMask.length) |
| | | { |
| | | return false; |
| | | } |
| | | for (int i = 0; i < prefixMask.length; i++) |
| | | { |
| | | if (!wildCard.get(i)) |
| | | { |
| | | if ((ruleMask[i] & prefixMask[i]) != (remoteMask[i] & prefixMask[i])) |
| | | { |
| | | Message message = |
| | | ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | return false; |
| | | } |
| | | else if(ruleString.startsWith(".")) |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 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(final String remoteHostName) |
| | | { |
| | | final 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])) |
| | | { |
| | | ruleType=RuleType.HOSTPATTERN; |
| | | return false; |
| | | } |
| | | else if(ruleString.startsWith("[") || |
| | | (ruleString.indexOf(':') != -1)) |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 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(final String remoteHostName) |
| | | { |
| | | final int len = remoteHostName.length() - hostPattern.length(); |
| | | return len > 0 |
| | | && remoteHostName.regionMatches(true, len, hostPattern, 0, |
| | | hostPattern.length()); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 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; |
| | | for (i = 0; prefix > 8; i++) |
| | | { |
| | | this.prefixMask[i] = (byte) 0xff; |
| | | prefix -= 8; |
| | | } |
| | | this.prefixMask[i] = (byte) ((0xff) << (8 - prefix)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 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(final String rule) |
| | | { |
| | | final String s[] = rule.split("\\.", -1); |
| | | if (s.length == IN4ADDRSZ) |
| | | { |
| | | for (int i = 0; i < IN4ADDRSZ; i++) |
| | | { |
| | | wildCard.set(i); |
| | | } |
| | | } |
| | | hostName = rule.split("\\.", -1); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 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(final String rule) throws ConfigException |
| | | { |
| | | // Note that '*' is valid in host rule |
| | | final String s[] = rule.split("^[0-9a-zA-z-.*]+"); |
| | | if (s.length > 0) |
| | | { |
| | | final Message message = ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | } |
| | | 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(final String rule) throws ConfigException |
| | | { |
| | | // quick check for invalid chars like " " |
| | | final String s[] = rule.split("^[0-9a-zA-z-.]+"); |
| | | if (s.length > 0) |
| | | { |
| | | final Message message = ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | } |
| | | hostPattern = rule; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 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(final String rule) throws ConfigException |
| | | { |
| | | final String[] s = rule.split("/", -1); |
| | | this.ruleMask = new byte[IN4ADDRSZ]; |
| | | this.prefixMask = new byte[IN4ADDRSZ]; |
| | | prefixMask(processPrefix(s, IPV4MAXPREFIX)); |
| | | processIPv4Subnet((s.length == 0) ? rule : s[0]); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 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(final String subnet) throws ConfigException |
| | | { |
| | | final String[] s = subnet.split("\\.", -1); |
| | | try |
| | | { |
| | | // Make sure we have four parts |
| | | if (s.length != IN4ADDRSZ) |
| | | { |
| | | final Message message = ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | } |
| | | for (int i = 0; i < IN4ADDRSZ; i++) |
| | | { |
| | | final String quad = s[i].trim(); |
| | | if (quad.equals("*")) |
| | | { |
| | | ruleType=RuleType.IPv6; |
| | | wildCard.set(i); // see wildcard mark bitset |
| | | } |
| | | 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 (String value : s) { |
| | | if (value.equals("*")) { |
| | | wildCount++; |
| | | continue; |
| | | } |
| | | //Looks like an ipv4 address |
| | | if (Character.isDigit(value.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); |
| | | this.ruleMask=new byte[IN4ADDRSZ]; |
| | | this.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) |
| | | { |
| | | Message message = |
| | | ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | final long val = Integer.parseInt(quad); |
| | | // must be between 0-255 |
| | | if ((val < 0) || (val > 0xff)) |
| | | { |
| | | final Message message = ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | } |
| | | ruleMask[i] = (byte) (val & 0xff); |
| | | } |
| | | 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) |
| | | { |
| | | Message message = |
| | | ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(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; |
| | | for( i=0;prefix > 8 ; i++) |
| | | { |
| | | this.prefixMask[i] = (byte) 0xff; |
| | | prefix -= 8; |
| | | } |
| | | this.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) { |
| | | Message message = |
| | | ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(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)) |
| | | { |
| | | Message message = |
| | | ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | } |
| | | ruleMask[i] = (byte) (val & 0xff); |
| | | } |
| | | } |
| | | } catch (NumberFormatException nfex) |
| | | { |
| | | Message message = |
| | | ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(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) ) |
| | | { |
| | | Message message = |
| | | ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | } |
| | | else if(s.length == 2) |
| | | { |
| | | //can't have wildcard with a prefix |
| | | if(s[0].indexOf('*') > -1) |
| | | { |
| | | Message message = |
| | | ERR_ADDRESSMASK_WILDCARD_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | } |
| | | prefix = Integer.parseInt(s[1]); |
| | | } |
| | | //must be between 0-maxprefix |
| | | if((prefix < 0) || (prefix > maxPrefix)) |
| | | { |
| | | Message message = |
| | | ERR_ADDRESSMASK_PREFIX_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | } |
| | | } |
| | | catch(NumberFormatException nfex) |
| | | { |
| | | Message msg = ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(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 matches one of the address masks in |
| | | * the provided collection. |
| | | * |
| | | * @param address |
| | | * The address to check. |
| | | * @param masks |
| | | * A collection of address masks to check. |
| | | * @return <CODE>true</CODE> if the provided address matches one of the |
| | | * given address masks, or <CODE>false</CODE> if it does not. |
| | | */ |
| | | public static boolean maskListContains(InetAddress address, |
| | | Collection<AddressMask> masks) |
| | | { |
| | | for (AddressMask mask : masks) |
| | | { |
| | | if (mask.match(address)) return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * Retrieves a string representation of this address mask. |
| | | * |
| | | * @return A string representation of this address mask. |
| | | */ |
| | | @Override |
| | | public String toString() |
| | | catch (final NumberFormatException nfex) |
| | | { |
| | | return ruleString; |
| | | final Message message = ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Main match function that determines which rule-type match |
| | | * function to use. |
| | | * @param address |
| | | * The address to check. |
| | | * @return <CODE>true</CODE>if one of the match functions found |
| | | * a match or <CODE>false</CODE>if not. |
| | | */ |
| | | private boolean match(InetAddress address) |
| | | |
| | | |
| | | /** |
| | | * The rule string is an IPv6 rule. Build both the prefix mask array and rule |
| | | * mask from the string. |
| | | * |
| | | * @param rule |
| | | * The rule string containing the IPv6 rule. |
| | | * @throws ConfigException |
| | | * If the rule string is not a valid IPv6 rule. |
| | | */ |
| | | private void processIPv6(final String rule) throws ConfigException |
| | | { |
| | | final String[] s = rule.split("/", -1); |
| | | InetAddress addr; |
| | | try |
| | | { |
| | | boolean ret=false; |
| | | |
| | | switch(ruleType) { |
| | | case IPv6: |
| | | case IPv4: |
| | | //this Address mask is an IPv4 rule |
| | | ret=matchAddress(address.getAddress()); |
| | | break; |
| | | |
| | | case HOST: |
| | | // HOST rule use hostname |
| | | ret=matchHostName(address.getHostName()); |
| | | break; |
| | | |
| | | case HOSTPATTERN: |
| | | //HOSTPATTERN rule |
| | | ret=matchPattern(address.getHostName()); |
| | | break; |
| | | |
| | | case ALLWILDCARD: |
| | | //first try ipv4 addr match, then hostname |
| | | ret=matchAddress(address.getAddress()); |
| | | if(!ret) |
| | | ret=matchHostName(address.getHostName()); |
| | | break; |
| | | } |
| | | return ret; |
| | | addr = InetAddress.getByName(s[0]); |
| | | } |
| | | |
| | | /** |
| | | * 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(); |
| | | return len > 0 && remoteHostName.regionMatches(true, len, |
| | | hostPattern, 0, hostPattern.length()); |
| | | catch (final UnknownHostException ex) |
| | | { |
| | | final Message message = ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | } |
| | | if (addr instanceof Inet6Address) |
| | | { |
| | | this.ruleType = RuleType.IPv6; |
| | | final Inet6Address addr6 = (Inet6Address) addr; |
| | | this.ruleMask = addr6.getAddress(); |
| | | this.prefixMask = new byte[IN6ADDRSZ]; |
| | | prefixMask(processPrefix(s, IPV6MAXPREFIX)); |
| | | } |
| | | else |
| | | { |
| | | /* |
| | | * The address might be an IPv4-compat address. Throw an error if the rule |
| | | * has a prefix. |
| | | */ |
| | | if (s.length == 2) |
| | | { |
| | | final Message message = ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | } |
| | | this.ruleMask = addr.getAddress(); |
| | | this.ruleType = RuleType.IPv4; |
| | | this.prefixMask = new byte[IN4ADDRSZ]; |
| | | prefixMask(processPrefix(s, IPV4MAXPREFIX)); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 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++) |
| | | |
| | | |
| | | /** |
| | | * 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(final String[] s, final 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)) |
| | | { |
| | | final Message message = ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | } |
| | | else if (s.length == 2) |
| | | { |
| | | // can't have wildcard with a prefix |
| | | if (s[0].indexOf('*') > -1) |
| | | { |
| | | if(!hostName[i].equals("*")) //skip if wildcard |
| | | { |
| | | if(!s[i].equalsIgnoreCase(hostName[i])) |
| | | return false; |
| | | } |
| | | final Message message = ERR_ADDRESSMASK_WILDCARD_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | } |
| | | return true; |
| | | prefix = Integer.parseInt(s[1]); |
| | | } |
| | | // must be between 0-maxprefix |
| | | if ((prefix < 0) || (prefix > maxPrefix)) |
| | | { |
| | | final Message message = ERR_ADDRESSMASK_PREFIX_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 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) |
| | | catch (final NumberFormatException nfex) |
| | | { |
| | | if(ruleType == RuleType.ALLWILDCARD) |
| | | return true; |
| | | if(prefixMask== null) |
| | | return false; |
| | | if(remoteMask.length != prefixMask.length) |
| | | return false; |
| | | 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; |
| | | final Message msg = ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(msg); |
| | | } |
| | | |
| | | /** |
| | | * The rule string is an IPv6 rule. Build both the prefix |
| | | * mask array and rule mask from the string. |
| | | * |
| | | * @param rule The rule string containing the IPv6 rule. |
| | | * @throws ConfigException If the rule string is not a valid |
| | | * IPv6 rule. |
| | | */ |
| | | private void processIPv6(String rule) throws ConfigException { |
| | | String[] s = rule.split("/", -1); |
| | | InetAddress addr; |
| | | try { |
| | | addr = InetAddress.getByName(s[0]); |
| | | } catch (UnknownHostException ex) { |
| | | Message message = |
| | | ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | } |
| | | if(addr instanceof Inet6Address) { |
| | | this.ruleType=RuleType.IPv6; |
| | | Inet6Address addr6 = (Inet6Address) addr; |
| | | this.ruleMask=addr6.getAddress(); |
| | | this.prefixMask=new byte[IN6ADDRSZ]; |
| | | prefixMask(processPrefix(s,IPV6MAXPREFIX)); |
| | | } else { |
| | | //The address might be an IPv4-compat address. |
| | | //Throw an error if the rule has a prefix. |
| | | if(s.length == 2) { |
| | | Message message = |
| | | ERR_ADDRESSMASK_FORMAT_DECODE_ERROR.get(); |
| | | throw new ConfigException(message); |
| | | } |
| | | this.ruleMask=addr.getAddress(); |
| | | this.ruleType=RuleType.IPv4; |
| | | this.prefixMask=new byte[IN4ADDRSZ]; |
| | | prefixMask(processPrefix(s,IPV4MAXPREFIX)); |
| | | } |
| | | } |
| | | return prefix; |
| | | } |
| | | } |
| | | |
| | | |