/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2008-2011 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.core.utils; import java.net.InetAddress; /** * <p>IPLike class.</p> * * @author ranger * @version $Id: $ */ public abstract class IPLike { private interface RangeMatcher { boolean match(final String value, final String range); } private static class HexRangeMatcher implements RangeMatcher { public boolean match(final String value, final String range) { return matchRangeHex(value, range); } } private static class DecimalRangeMatcher implements RangeMatcher { public boolean match(final String value, final String range) { return matchRange(value, range); } } public static boolean matches(final InetAddress address, final String pattern) { return matches(InetAddressUtils.str(address), pattern); } /** * <p>matches</p> * * @param address a {@link java.lang.String} object. * @param pattern a {@link java.lang.String} object. * @return a boolean. */ public static boolean matches(String address, String pattern) { String[] hostOctets = null; String[] matchOctets = null; RangeMatcher matcher = null; int numberOfOctets = 4; if (address.indexOf(':') >= 0) { // First try and match the scope identifier final String[] patternAndScope = pattern.split("%"); pattern = patternAndScope[0]; final String[] addressAndScope = address.split("%"); address = addressAndScope[0]; if (patternAndScope.length < 2) { // Do nothing; there was no pattern specified for the scope identifier } else if (patternAndScope.length == 2) { if (addressAndScope.length < 2) { return false; } else if (addressAndScope.length == 2) { // Assume that scope identifiers are always decimal if (!matchNumericListOrRange(addressAndScope[1], patternAndScope[1], new DecimalRangeMatcher())) { return false; } } else { throw new IllegalArgumentException("Illegal scope identifier in address: " + address); } } else { throw new IllegalArgumentException("Illegal scope identifier filter: " + pattern); } hostOctets = address.split("\\:", 0); matchOctets = pattern.split("\\:", 0); numberOfOctets = 8; matcher = new HexRangeMatcher(); } else { hostOctets = address.split("\\.", 0); matchOctets = pattern.split("\\.", 0); numberOfOctets = 4; matcher = new DecimalRangeMatcher(); } if (hostOctets.length != numberOfOctets) { throw new IllegalArgumentException("Malformatted IP address: " + address); } else if (matchOctets.length != numberOfOctets) { throw new IllegalArgumentException("Malformatted IPLIKE match expression: " + pattern); } for (int i = 0; i < numberOfOctets; i++) { if (!matchNumericListOrRange(hostOctets[i], matchOctets[i], matcher)) { return false; } } return true; } public static boolean matchNumericListOrRange(final String value, final String patterns) { return matchNumericListOrRange(value, patterns, new DecimalRangeMatcher()); } /** * Use this method to match ranges, lists, and specific number strings * such as: * "200-300" or "200,300,501-700" * "*" matches any * This method is commonly used for matching IP octets or ports * * @param value a {@link java.lang.String} object. * @param patterns a {@link java.lang.String} object. * @return a boolean. */ public static boolean matchNumericListOrRange(final String value, final String patterns, final RangeMatcher matcher) { final String patternList[] = patterns.split(",", 0); for (final String element : patternList) { if (matcher.match(value, element)) { return true; } } return false; } /** * Helper method in support of matchNumericListOrRange * * @param value a {@link java.lang.String} object. * @param pattern a {@link java.lang.String} object. * @return a boolean. */ public static boolean matchRange(final String value, final String pattern) { final int dashCount = countChar('-', pattern); if ("*".equals(pattern)) { return true; } else if (dashCount == 0) { return Long.parseLong(pattern, 10) == Long.parseLong(value, 10); } else if (dashCount > 1) { return false; } else if (dashCount == 1) { final String ar[] = pattern.split("-"); final long rangeBegin = Long.parseLong(ar[0]); final long rangeEnd = Long.parseLong(ar[1]); final long ip = Long.parseLong(value); return (ip >= rangeBegin && ip <= rangeEnd); } return false; } /** * Helper method in support of matchNumericListOrRange * * @param value a {@link java.lang.String} object. * @param pattern a {@link java.lang.String} object. * @return a boolean. */ public static boolean matchRangeHex(final String value, final String pattern) { final int dashCount = countChar('-', pattern); if ("*".equals(pattern)) { return true; } else if (dashCount == 0) { // Convert values to hex integers and compare return Long.parseLong(pattern, 16) == Long.parseLong(value, 16); } else if (dashCount > 1) { return false; } else if (dashCount == 1) { final String ar[] = pattern.split("-"); final long rangeBegin = Long.parseLong(ar[0], 16); final long rangeEnd = Long.parseLong(ar[1], 16); final long ip = Long.parseLong(value, 16); return (ip >= rangeBegin && ip <= rangeEnd); } return false; } /** * <p>countChar</p> * * @param charIn a char. * @param stingIn a {@link java.lang.String} object. * @return a int. */ public static int countChar(final char charIn, final String stingIn) { int charCount = 0; int charIndex = 0; for (int i=0; i<stingIn.length(); i++) { charIndex = stingIn.indexOf(charIn, i); if (charIndex != -1) { charCount++; i = charIndex +1; } } return charCount; } }