IpUtils.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. package com.ruoyi.common.utils.ip;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.net.InetAddress;
  6. import java.net.URL;
  7. import java.net.UnknownHostException;
  8. import java.util.ArrayList;
  9. import java.util.List;
  10. import java.util.concurrent.Callable;
  11. import java.util.concurrent.ExecutionException;
  12. import java.util.concurrent.ExecutorService;
  13. import java.util.concurrent.Executors;
  14. import java.util.regex.Pattern;
  15. import javax.servlet.http.HttpServletRequest;
  16. import com.ruoyi.common.utils.ServletUtils;
  17. import com.ruoyi.common.utils.StringUtils;
  18. /**
  19. * 获取IP方法
  20. *
  21. * @author ruoyi
  22. */
  23. public class IpUtils
  24. {
  25. public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
  26. // 匹配 ip
  27. public final static String REGX_IP = "((" + REGX_0_255 + "\\.){3}" + REGX_0_255 + ")";
  28. public final static String REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + REGX_0_255 + "(\\.\\*){3})|(" + REGX_0_255 + "\\." + REGX_0_255 + ")(\\.\\*){2}" + "|((" + REGX_0_255 + "\\.){3}\\*))";
  29. // 匹配网段
  30. public final static String REGX_IP_SEG = "(" + REGX_IP + "\\-" + REGX_IP + ")";
  31. /**
  32. * 获取客户端IP
  33. *
  34. * @return IP地址
  35. */
  36. public static String getIpAddr()
  37. {
  38. return getIpAddr(ServletUtils.getRequest());
  39. }
  40. /**
  41. * 获取客户端IP
  42. *
  43. * @param request 请求对象
  44. * @return IP地址
  45. */
  46. public static String getIpAddr(HttpServletRequest request)
  47. {
  48. if (request == null)
  49. {
  50. return "unknown";
  51. }
  52. String ip = request.getHeader("x-forwarded-for");
  53. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
  54. {
  55. ip = request.getHeader("Proxy-Client-IP");
  56. }
  57. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
  58. {
  59. ip = request.getHeader("X-Forwarded-For");
  60. }
  61. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
  62. {
  63. ip = request.getHeader("WL-Proxy-Client-IP");
  64. }
  65. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
  66. {
  67. ip = request.getHeader("X-Real-IP");
  68. }
  69. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
  70. {
  71. ip = request.getRemoteAddr();
  72. }
  73. return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
  74. }
  75. /**
  76. * 检查是否为内部IP地址
  77. *
  78. * @param ip IP地址
  79. * @return 结果
  80. */
  81. public static boolean internalIp(String ip)
  82. {
  83. byte[] addr = textToNumericFormatV4(ip);
  84. return internalIp(addr) || "127.0.0.1".equals(ip);
  85. }
  86. /**
  87. * 检查是否为内部IP地址
  88. *
  89. * @param addr byte地址
  90. * @return 结果
  91. */
  92. private static boolean internalIp(byte[] addr)
  93. {
  94. if (StringUtils.isNull(addr) || addr.length < 2)
  95. {
  96. return true;
  97. }
  98. final byte b0 = addr[0];
  99. final byte b1 = addr[1];
  100. // 10.x.x.x/8
  101. final byte SECTION_1 = 0x0A;
  102. // 172.16.x.x/12
  103. final byte SECTION_2 = (byte) 0xAC;
  104. final byte SECTION_3 = (byte) 0x10;
  105. final byte SECTION_4 = (byte) 0x1F;
  106. // 192.168.x.x/16
  107. final byte SECTION_5 = (byte) 0xC0;
  108. final byte SECTION_6 = (byte) 0xA8;
  109. switch (b0)
  110. {
  111. case SECTION_1:
  112. return true;
  113. case SECTION_2:
  114. if (b1 >= SECTION_3 && b1 <= SECTION_4)
  115. {
  116. return true;
  117. }
  118. case SECTION_5:
  119. switch (b1)
  120. {
  121. case SECTION_6:
  122. return true;
  123. }
  124. default:
  125. return false;
  126. }
  127. }
  128. /**
  129. * 将IPv4地址转换成字节
  130. *
  131. * @param text IPv4地址
  132. * @return byte 字节
  133. */
  134. public static byte[] textToNumericFormatV4(String text)
  135. {
  136. if (text.length() == 0)
  137. {
  138. return null;
  139. }
  140. byte[] bytes = new byte[4];
  141. String[] elements = text.split("\\.", -1);
  142. try
  143. {
  144. long l;
  145. int i;
  146. switch (elements.length)
  147. {
  148. case 1:
  149. l = Long.parseLong(elements[0]);
  150. if ((l < 0L) || (l > 4294967295L))
  151. {
  152. return null;
  153. }
  154. bytes[0] = (byte) (int) (l >> 24 & 0xFF);
  155. bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
  156. bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
  157. bytes[3] = (byte) (int) (l & 0xFF);
  158. break;
  159. case 2:
  160. l = Integer.parseInt(elements[0]);
  161. if ((l < 0L) || (l > 255L))
  162. {
  163. return null;
  164. }
  165. bytes[0] = (byte) (int) (l & 0xFF);
  166. l = Integer.parseInt(elements[1]);
  167. if ((l < 0L) || (l > 16777215L))
  168. {
  169. return null;
  170. }
  171. bytes[1] = (byte) (int) (l >> 16 & 0xFF);
  172. bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
  173. bytes[3] = (byte) (int) (l & 0xFF);
  174. break;
  175. case 3:
  176. for (i = 0; i < 2; ++i)
  177. {
  178. l = Integer.parseInt(elements[i]);
  179. if ((l < 0L) || (l > 255L))
  180. {
  181. return null;
  182. }
  183. bytes[i] = (byte) (int) (l & 0xFF);
  184. }
  185. l = Integer.parseInt(elements[2]);
  186. if ((l < 0L) || (l > 65535L))
  187. {
  188. return null;
  189. }
  190. bytes[2] = (byte) (int) (l >> 8 & 0xFF);
  191. bytes[3] = (byte) (int) (l & 0xFF);
  192. break;
  193. case 4:
  194. for (i = 0; i < 4; ++i)
  195. {
  196. l = Integer.parseInt(elements[i]);
  197. if ((l < 0L) || (l > 255L))
  198. {
  199. return null;
  200. }
  201. bytes[i] = (byte) (int) (l & 0xFF);
  202. }
  203. break;
  204. default:
  205. return null;
  206. }
  207. }
  208. catch (NumberFormatException e)
  209. {
  210. return null;
  211. }
  212. return bytes;
  213. }
  214. /**
  215. * 获取IP地址
  216. *
  217. * @return 本地IP地址
  218. */
  219. public static String getHostIp()
  220. {
  221. try
  222. {
  223. return InetAddress.getLocalHost().getHostAddress();
  224. }
  225. catch (UnknownHostException e)
  226. {
  227. }
  228. return "127.0.0.1";
  229. }
  230. /**
  231. * 获取主机名
  232. *
  233. * @return 本地主机名
  234. */
  235. public static String getHostName()
  236. {
  237. try
  238. {
  239. return InetAddress.getLocalHost().getHostName();
  240. }
  241. catch (UnknownHostException e)
  242. {
  243. }
  244. return "未知";
  245. }
  246. /**
  247. * 从多级反向代理中获得第一个非unknown IP地址
  248. *
  249. * @param ip 获得的IP地址
  250. * @return 第一个非unknown IP地址
  251. */
  252. public static String getMultistageReverseProxyIp(String ip)
  253. {
  254. // 多级反向代理检测
  255. if (ip != null && ip.indexOf(",") > 0)
  256. {
  257. final String[] ips = ip.trim().split(",");
  258. for (String subIp : ips)
  259. {
  260. if (false == isUnknown(subIp))
  261. {
  262. ip = subIp;
  263. break;
  264. }
  265. }
  266. }
  267. return StringUtils.substring(ip, 0, 255);
  268. }
  269. /**
  270. * 检测给定字符串是否为未知,多用于检测HTTP请求相关
  271. *
  272. * @param checkString 被检测的字符串
  273. * @return 是否未知
  274. */
  275. public static boolean isUnknown(String checkString)
  276. {
  277. return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
  278. }
  279. /**
  280. * 是否为IP
  281. */
  282. public static boolean isIP(String ip)
  283. {
  284. return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP);
  285. }
  286. /**
  287. * 是否为IP,或 *为间隔的通配符地址
  288. */
  289. public static boolean isIpWildCard(String ip)
  290. {
  291. return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP_WILDCARD);
  292. }
  293. /**
  294. * 检测参数是否在ip通配符里
  295. */
  296. public static boolean ipIsInWildCardNoCheck(String ipWildCard, String ip)
  297. {
  298. String[] s1 = ipWildCard.split("\\.");
  299. String[] s2 = ip.split("\\.");
  300. boolean isMatchedSeg = true;
  301. for (int i = 0; i < s1.length && !s1[i].equals("*"); i++)
  302. {
  303. if (!s1[i].equals(s2[i]))
  304. {
  305. isMatchedSeg = false;
  306. break;
  307. }
  308. }
  309. return isMatchedSeg;
  310. }
  311. /**
  312. * 是否为特定格式如:“10.10.10.1-10.10.10.99”的ip段字符串
  313. */
  314. public static boolean isIPSegment(String ipSeg)
  315. {
  316. return StringUtils.isNotBlank(ipSeg) && ipSeg.matches(REGX_IP_SEG);
  317. }
  318. /**
  319. * 判断ip是否在指定网段中
  320. */
  321. public static boolean ipIsInNetNoCheck(String iparea, String ip)
  322. {
  323. int idx = iparea.indexOf('-');
  324. String[] sips = iparea.substring(0, idx).split("\\.");
  325. String[] sipe = iparea.substring(idx + 1).split("\\.");
  326. String[] sipt = ip.split("\\.");
  327. long ips = 0L, ipe = 0L, ipt = 0L;
  328. for (int i = 0; i < 4; ++i)
  329. {
  330. ips = ips << 8 | Integer.parseInt(sips[i]);
  331. ipe = ipe << 8 | Integer.parseInt(sipe[i]);
  332. ipt = ipt << 8 | Integer.parseInt(sipt[i]);
  333. }
  334. if (ips > ipe)
  335. {
  336. long t = ips;
  337. ips = ipe;
  338. ipe = t;
  339. }
  340. return ips <= ipt && ipt <= ipe;
  341. }
  342. /**
  343. * 校验ip是否符合过滤串规则
  344. *
  345. * @param filter 过滤IP列表,支持后缀'*'通配,支持网段如:`10.10.10.1-10.10.10.99`
  346. * @param ip 校验IP地址
  347. * @return boolean 结果
  348. */
  349. public static boolean isMatchedIp(String filter, String ip)
  350. {
  351. if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(ip))
  352. {
  353. return false;
  354. }
  355. String[] ips = filter.split(";");
  356. for (String iStr : ips)
  357. {
  358. if (isIP(iStr) && iStr.equals(ip))
  359. {
  360. return true;
  361. }
  362. else if (isIpWildCard(iStr) && ipIsInWildCardNoCheck(iStr, ip))
  363. {
  364. return true;
  365. }
  366. else if (isIPSegment(iStr) && ipIsInNetNoCheck(iStr, ip))
  367. {
  368. return true;
  369. }
  370. }
  371. return false;
  372. }
  373. /**
  374. * 2024-12-16 fangqing 加入 获取外网IP地址
  375. */
  376. /**
  377. * IP 地址校验的正则表达式
  378. */
  379. private static final Pattern IPV4_PATTERN = Pattern.compile("^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");
  380. /**
  381. * 获取 IP 地址的服务列表
  382. */
  383. private static final String[] IPV4_SERVICES = {
  384. "http://checkip.amazonaws.com/",
  385. "https://ipv4.icanhazip.com/",
  386. "http://bot.whatismyipaddress.com/"
  387. // and so on ...
  388. };
  389. public static String get() throws ExecutionException, InterruptedException {
  390. List<Callable<String>> callables = new ArrayList<>();
  391. for (String ipService : IPV4_SERVICES) {
  392. callables.add(() -> get(ipService));
  393. }
  394. ExecutorService executorService = Executors.newCachedThreadPool();
  395. try {
  396. // 返回第一个成功获取的 IP
  397. return executorService.invokeAny(callables);
  398. } finally {
  399. executorService.shutdown();
  400. }
  401. }
  402. private static String get(String url) throws IOException {
  403. try (BufferedReader in = new BufferedReader(new InputStreamReader(new URL(url).openStream()))) {
  404. String ip = in.readLine();
  405. if (IPV4_PATTERN.matcher(ip).matches()) {
  406. return ip;
  407. } else {
  408. throw new IOException("invalid IPv4 address: " + ip);
  409. }
  410. }
  411. }
  412. }