001/* 002 * Copyright 2015-2024 the original author or authors 003 * 004 * This software is licensed under the Apache License, Version 2.0, 005 * the GNU Lesser General Public License version 2 or later ("LGPL") 006 * and the WTFPL. 007 * You may choose either license to govern your use of this software only 008 * upon the condition that you accept all of the terms of either 009 * the Apache License 2.0, the LGPL 2.1+ or the WTFPL. 010 */ 011package org.minidns.util; 012 013import java.net.Inet4Address; 014import java.net.Inet6Address; 015import java.net.InetAddress; 016import java.net.UnknownHostException; 017import java.util.regex.Pattern; 018 019import org.minidns.dnsname.DnsName; 020 021public class InetAddressUtil { 022 023 public static Inet4Address ipv4From(CharSequence cs) { 024 InetAddress inetAddress; 025 try { 026 inetAddress = InetAddress.getByName(cs.toString()); 027 } catch (UnknownHostException e) { 028 throw new IllegalArgumentException(e); 029 } 030 if (inetAddress instanceof Inet4Address) { 031 return (Inet4Address) inetAddress; 032 } 033 throw new IllegalArgumentException(); 034 } 035 036 public static Inet6Address ipv6From(CharSequence cs) { 037 InetAddress inetAddress; 038 try { 039 inetAddress = InetAddress.getByName(cs.toString()); 040 } catch (UnknownHostException e) { 041 throw new IllegalArgumentException(e); 042 } 043 if (inetAddress instanceof Inet6Address) { 044 return (Inet6Address) inetAddress; 045 } 046 throw new IllegalArgumentException(); 047 } 048 049 // IPV4_REGEX from http://stackoverflow.com/a/46168/194894 by Kevin Wong (http://stackoverflow.com/users/4792/kevin-wong) licensed under 050 // CC BY-SA 3.0. 051 private static final Pattern IPV4_PATTERN = Pattern.compile("\\A(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z"); 052 053 public static boolean isIpV4Address(CharSequence address) { 054 if (address == null) { 055 return false; 056 } 057 return IPV4_PATTERN.matcher(address).matches(); 058 } 059 060 // IPv6 Regular Expression from http://stackoverflow.com/a/17871737/194894 by David M. Syzdek 061 // (http://stackoverflow.com/users/903194/david-m-syzdek) licensed under CC BY-SA 3.0. 062 private static final Pattern IPV6_PATTERN = Pattern.compile( 063 "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"); 064 065 public static boolean isIpV6Address(CharSequence address) { 066 if (address == null) { 067 return false; 068 } 069 return IPV6_PATTERN.matcher(address).matches(); 070 } 071 072 public static boolean isIpAddress(CharSequence address) { 073 return isIpV6Address(address) || isIpV4Address(address); 074 } 075 076 public static InetAddress convertToInetAddressIfPossible(CharSequence address) { 077 if (!isIpAddress(address)) { 078 return null; 079 } 080 081 String addressString = address.toString(); 082 try { 083 return InetAddress.getByName(addressString); 084 } catch (UnknownHostException e) { 085 // Should never happen. 086 throw new AssertionError(e); 087 } 088 } 089 090 public static DnsName reverseIpAddressOf(Inet6Address inet6Address) { 091 final String ipAddress = inet6Address.getHostAddress(); 092 final String[] ipAddressParts = ipAddress.split(":"); 093 094 String[] parts = new String[32]; 095 int currentPartNum = 0; 096 for (int i = ipAddressParts.length - 1; i >= 0; i--) { 097 final String currentPart = ipAddressParts[i]; 098 final int missingPlaces = 4 - currentPart.length(); 099 for (int j = 0; j < missingPlaces; j++) { 100 parts[currentPartNum++] = "0"; 101 } 102 for (int j = 0; j < currentPart.length(); j++) { 103 parts[currentPartNum++] = Character.toString(currentPart.charAt(j)); 104 } 105 } 106 107 return DnsName.from(parts); 108 } 109 110 public static DnsName reverseIpAddressOf(Inet4Address inet4Address) { 111 final String[] ipAddressParts = inet4Address.getHostAddress().split("\\."); 112 assert ipAddressParts.length == 4; 113 114 return DnsName.from(ipAddressParts); 115 } 116}