Skip to content

Instantly share code, notes, and snippets.

@wenzhihong2003
Forked from pfmiles/Ipv4WhiteList.java
Created April 10, 2014 04:51
Show Gist options
  • Save wenzhihong2003/10343493 to your computer and use it in GitHub Desktop.
Save wenzhihong2003/10343493 to your computer and use it in GitHub Desktop.
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);
}
}
}
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