-
-
Save wenzhihong2003/10343493 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package xxx; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.Map; | |
import java.util.Set; | |
import org.apache.oro.text.regex.MalformedPatternException; | |
import org.apache.oro.text.regex.Pattern; | |
import org.apache.oro.text.regex.Perl5Compiler; | |
import org.apache.oro.text.regex.Perl5Matcher; | |
/** | |
* 用作匹配ipv4地址黑/白名单的工具 | |
* | |
* @author pf-miles 2014-3-7 下午2:10:43 | |
*/ | |
public class Ipv4WhiteList { | |
// 整体语法正确性校验正则 | |
private static final Pattern allPat; | |
private static final Pattern blankPat; | |
// num cache | |
private static final Integer[] numTab = new Integer[256]; | |
static { | |
try { | |
allPat = new Perl5Compiler().compile("^\\s*(\\d{1,3}(\\-\\d{1,3})?\\.\\d{1,3}(\\-\\d{1,3})?\\.\\d{1,3}(\\-\\d{1,3})?\\.\\d{1,3}(\\-\\d{1,3})?(\\s*,\\s*\\d{1,3}(\\-\\d{1,3})?\\.\\d{1,3}(\\-\\d{1,3})?\\.\\d{1,3}(\\-\\d{1,3})?\\.\\d{1,3}(\\-\\d{1,3})?)*)?\\s*$"); | |
blankPat = new Perl5Compiler().compile("^\\s*$"); | |
} catch (MalformedPatternException e) { | |
throw new RuntimeException(e); | |
} | |
for (int i = 0; i < 256; i++) | |
numTab[i] = i; | |
} | |
private Map<Integer, Set<String>> lv0Map = new HashMap<Integer, Set<String>>(); | |
private Map<Integer, Set<String>> lv1Map = new HashMap<Integer, Set<String>>(); | |
private Map<Integer, Set<String>> lv2Map = new HashMap<Integer, Set<String>>(); | |
private Map<Integer, Set<String>> lv3Map = new HashMap<Integer, Set<String>>(); | |
/** | |
* 编译、构造匹配内容 | |
* | |
* @param ipRules 符合ipList语法规范的ip规则,支持精确ip,如“127.0.0.1”和范围ip, 如"192.168.1-2.5-103"或"204-208.119.5-13.0-255"两种形式 | |
*/ | |
public Ipv4WhiteList(String ipRules){ | |
if (ipRules == null || new Perl5Matcher().matches(ipRules, blankPat)) return; | |
if (!new Perl5Matcher().matches(ipRules, allPat)) { | |
throw new RuntimeException("Ip rules syntax error."); | |
} | |
String[] ips = ipRules.split(","); | |
if (ips == null || ips.length == 0) return; | |
for (String ip : ips) { | |
ip = ip.trim(); | |
addToMapping(ip); | |
} | |
} | |
private void addToMapping(String ip) { | |
String[] segs = ip.split("\\."); | |
if (segs[0].contains("-")) { | |
String[] p = segs[0].split("\\-"); | |
int from = Integer.parseInt(p[0]); | |
int to = Integer.parseInt(p[1]); | |
for (int i = from; i <= to; i++) | |
putOnMap(lv0Map, getCachedInteger(i), ip); | |
} else { | |
putOnMap(lv0Map, getIntegerFromStr(segs[0]), ip); | |
} | |
if (segs[1].contains("-")) { | |
String[] p = segs[1].split("\\-"); | |
int from = Integer.parseInt(p[0]); | |
int to = Integer.parseInt(p[1]); | |
for (int i = from; i <= to; i++) | |
putOnMap(lv1Map, getCachedInteger(i), ip); | |
} else { | |
putOnMap(lv1Map, getIntegerFromStr(segs[1]), ip); | |
} | |
if (segs[2].contains("-")) { | |
String[] p = segs[2].split("\\-"); | |
int from = Integer.parseInt(p[0]); | |
int to = Integer.parseInt(p[1]); | |
for (int i = from; i <= to; i++) | |
putOnMap(lv2Map, getCachedInteger(i), ip); | |
} else { | |
putOnMap(lv2Map, getIntegerFromStr(segs[2]), ip); | |
} | |
if (segs[3].contains("-")) { | |
String[] p = segs[3].split("\\-"); | |
int from = Integer.parseInt(p[0]); | |
int to = Integer.parseInt(p[1]); | |
for (int i = from; i <= to; i++) | |
putOnMap(lv3Map, getCachedInteger(i), ip); | |
} else { | |
putOnMap(lv3Map, getIntegerFromStr(segs[3]), ip); | |
} | |
} | |
private void putOnMap(Map<Integer, Set<String>> map, Integer key, String ip) { | |
Set<String> set = null; | |
if (map.containsKey(key)) { | |
set = map.get(key); | |
} else { | |
set = new HashSet<String>(); | |
map.put(key, set); | |
} | |
set.add(ip); | |
} | |
/** | |
* 判断是否在ip名单中 | |
* | |
* @param ip | |
* @return | |
*/ | |
public boolean isIn(String ip) { | |
if (ip == null) return false; | |
String[] segs = ip.trim().split("\\."); | |
if (segs.length != 4) return false; | |
Set<String> set = lv0Map.get(Integer.parseInt(segs[0])); | |
if (set == null || set.isEmpty()) return false; | |
set = intersect(set, lv1Map.get(Integer.parseInt(segs[1]))); | |
if (set == null || set.isEmpty()) return false; | |
set = intersect(set, lv2Map.get(Integer.parseInt(segs[2]))); | |
if (set == null || set.isEmpty()) return false; | |
set = intersect(set, lv3Map.get(Integer.parseInt(segs[3]))); | |
if (set == null || set.isEmpty()) return false; | |
return true; | |
} | |
private Set<String> intersect(Set<String> s1, Set<String> s2) { | |
if (s2 == null || s2.isEmpty()) return null; | |
Set<String> ret = new HashSet<String>(); | |
for (String s : s1) | |
if (s2.contains(s)) ret.add(s); | |
return ret; | |
} | |
private static Integer getIntegerFromStr(String str) { | |
return getCachedInteger(Integer.parseInt(str)); | |
} | |
private static Integer getCachedInteger(int i) { | |
try { | |
return numTab[i]; | |
} catch (ArrayIndexOutOfBoundsException e) { | |
throw new RuntimeException( | |
"Illegal ipv4 address, each part of a address must be in range 0 ~ 255. But found: " | |
+ i); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package xxx; | |
import java.lang.reflect.Field; | |
import java.util.Map; | |
import java.util.Set; | |
import junit.framework.Assert; | |
import org.junit.Test; | |
/** | |
* @author pf-miles 2014-3-10 下午1:37:29 | |
*/ | |
public class Ipv4WhiteListTest { | |
@Test | |
public void testEmpty() { | |
Ipv4WhiteList list = new Ipv4WhiteList(null); | |
Assert.assertFalse(list.isIn("192.168.0.1")); | |
list = new Ipv4WhiteList(" \t "); | |
Assert.assertFalse(list.isIn("192.168.0.1")); | |
} | |
@Test | |
public void testNormal() { | |
Ipv4WhiteList list = new Ipv4WhiteList(" 192.168.0.1 , 192.168.0.3 "); | |
Assert.assertTrue(list.isIn(" 192.168.0.1 ")); | |
Assert.assertTrue(list.isIn(" 192.168.0.3 ")); | |
Assert.assertFalse(list.isIn(" 192.168.0.2 ")); | |
list = new Ipv4WhiteList(" 192.168-170.0.1 , 192.172-175.0.3 "); | |
Assert.assertTrue(list.isIn("192.169.0.1")); | |
Assert.assertFalse(list.isIn("192.171.0.1")); | |
} | |
@Test | |
public void testEdge() { | |
Ipv4WhiteList list = new Ipv4WhiteList(" 190-193.165-168.0-3.100-103 , 190-193.165-168.5-7.100-103 "); | |
Assert.assertFalse(list.isIn("190.165.0.99")); | |
Assert.assertTrue(list.isIn("190.165.0.100")); | |
Assert.assertTrue(list.isIn("193.168.3.103")); | |
Assert.assertFalse(list.isIn("193.168.4.103")); | |
Assert.assertTrue(list.isIn("190.165.5.100")); | |
Assert.assertTrue(list.isIn("193.168.7.103")); | |
Assert.assertFalse(list.isIn("193.168.8.103")); | |
} | |
@Test | |
public void testOutOfRange() { | |
try { | |
new Ipv4WhiteList(" 192.256.0.1 "); | |
Assert.fail(); | |
} catch (Exception e) { | |
Assert.assertTrue(true); | |
} | |
} | |
// @Test | |
// public void testMemStruct() throws NoSuchFieldException, SecurityException, IllegalArgumentException, | |
// IllegalAccessException { | |
// Ipv4WhiteList list = new Ipv4WhiteList(" 190-192.165.0-2.100 , 191.164-166.3.99-101 "); | |
// Field f0 = list.getClass().getDeclaredField("lv0Map"); | |
// Field f1 = list.getClass().getDeclaredField("lv1Map"); | |
// Field f2 = list.getClass().getDeclaredField("lv2Map"); | |
// Field f3 = list.getClass().getDeclaredField("lv3Map"); | |
// f0.setAccessible(true); | |
// f1.setAccessible(true); | |
// f2.setAccessible(true); | |
// f3.setAccessible(true); | |
// System.out.println(f0.get(list)); | |
// System.out.println(f1.get(list)); | |
// System.out.println(f2.get(list)); | |
// System.out.println(f3.get(list)); | |
// } | |
@SuppressWarnings("unchecked") | |
@Test | |
public void testNumCache() throws Exception { | |
Ipv4WhiteList list = new Ipv4WhiteList(" 190-195.168.0.192-197 , 10.4.25-26.190-199 "); | |
Field f0 = list.getClass().getDeclaredField("lv0Map"); | |
f0.setAccessible(true); | |
Map<Integer, Set<String>> lv0Map = (Map<Integer, Set<String>>) f0.get(list); | |
Field f3 = list.getClass().getDeclaredField("lv3Map"); | |
f3.setAccessible(true); | |
Map<Integer, Set<String>> lv3Map = (Map<Integer, Set<String>>) f3.get(list); | |
Object lv0n193 = null; | |
for (Integer i : lv0Map.keySet()) { | |
if (i.equals(193)) { | |
lv0n193 = i; | |
break; | |
} | |
} | |
Object lv3n193 = null; | |
for (Integer i : lv3Map.keySet()) { | |
if (i.equals(193)) { | |
lv3n193 = i; | |
break; | |
} | |
} | |
Assert.assertTrue(lv0n193 == lv3n193); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment