收到一个需求,需要判断IP是否来自中国。
判断IP来源,很早之前自己也感兴趣,一直没有去了解如何实现。
今天正好搜索了一下相关的文章。
亚洲所有相关分配的IP段可以从 http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest 查询。
从里面解释后即可实现判断IP是否为中国。
没有找到java的代码,就自己写了一份,供其它朋友使用。
将下载下来的 delegated-apnic-latest 放在 classpath下即可。
import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.List; import java.util.Map; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.assertj.core.util.Lists; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Maps; public class IpUtil { private static final String FILE_NAME = "delegated-apnic-latest"; // 只存放属于中国的ip段 private static Map<Integer, List<int[]>> chinaIps = Maps.newHashMap(); static { init(); } public static void init() { try { // ip格式: add1.add2.add3.add4 // key为 : add1*256+add2 // value为int[2]: int[0]存的add3*256+add4的开始ip int[4]存的结束ip Map<Integer, List<int[]>> map = Maps.newHashMap(); InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream(FILE_NAME); List<String> lines = IOUtils.readLines(input, StandardCharsets.UTF_8); for (String line : lines) { if (line.startsWith("apnic|CN|ipv4|")) { // 只处理属于中国的ipv4地址 String[] strs = line.split("\\|"); String ip = strs[3]; String[] add = ip.split("\\."); int count = Integer.valueOf(strs[4]); int startIp = Integer.parseInt(add[0]) * 256 + Integer.parseInt(add[1]); while (count > 0) { if (count >= 65536) { // add1,add2 整段都是中国ip chinaIps.put(startIp, Collections.EMPTY_LIST); count -= 65536; startIp += 1; } else { int[] ipRange = new int[2]; ipRange[0] = Integer.parseInt(add[2]) * 256 + Integer.parseInt(add[3]); ipRange[1] = ipRange[0] + count; count -= count; List<int[]> list = map.get(startIp); if (list == null) { list = Lists.newArrayList(); map.put(startIp, list); } list.add(ipRange); } } } } chinaIps.putAll(map); } catch (Exception e) { logger.error("ERROR", e); } } public static boolean isChinaIp(String ip) { if (StringUtils.isEmpty(ip)) { return false; } String[] strs = ip.split("\\."); if (strs.length != 4) { return false; } int key = Integer.valueOf(strs[0]) * 256 + Integer.valueOf(strs[1]); List<int[]> list = chinaIps.get(key); if (list == null) { return false; } if (list.size() == 0) { // 整段都是中国ip return true; } int ipValue = Integer.valueOf(strs[2]) * 256 + Integer.valueOf(strs[3]); for (int[] ipRange : list) { if (ipValue >= ipRange[0] && ipValue <= ipRange[1]) { return true; } } return false; } private static final Logger logger = LoggerFactory.getLogger(IpUtil.class); }
如果扩展这个代码后,可以增加判断IP属于哪个国家。
如果在判断IP属于哪个城市,可能得需要 http://dev.maxmind.com/zh-hans/geoip/geoip2/
参考:
https://www.zhihu.com/question/19794443
http://xixitalk.github.io/blog/2013/03/11/func-is-china-ip/
😆 😈 😈 😈 😈 😈 😈
chinaIps = map; 全部包括的被覆盖了。。。。
多谢指出,已修改
66行chinaIps = map;应该是chinaIps.putAll(map);
多谢指出,已修改
博主你好,代码中startIp += 1;是为啥
请问下载下来的 delegated-apnic-latest 文件是什么格式的,还是什么格式都可以
没有IPv6的判断