InetAddresses: cleanup and implement final fallback

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2019-10-18 13:25:45 +02:00
parent f8a3e9b332
commit bc0111f895

View File

@ -6,35 +6,34 @@
package com.wireguard.config; package com.wireguard.config;
import android.os.Build; import android.os.Build;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.Inet4Address; import java.net.Inet4Address;
import java.net.Inet6Address; import java.net.Inet6Address;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
/** /**
* Utility methods for creating instances of {@link InetAddress}. * Utility methods for creating instances of {@link InetAddress}.
*/ */
public final class InetAddresses { public final class InetAddresses {
private static Method PARSER_METHOD; @Nullable private static final Method PARSER_METHOD;
private static final Pattern WONT_TOUCH_RESOLVER = Pattern.compile("^(((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?)|((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))$");
static {
private static Method getParserMethod() { Method m = null;
if (PARSER_METHOD != null)
return PARSER_METHOD;
try { try {
// This method is only present on Android. if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
// noinspection JavaReflectionMemberAccess // noinspection JavaReflectionMemberAccess
PARSER_METHOD = InetAddress.class.getMethod("parseNumericAddress", String.class); m = InetAddress.class.getMethod("parseNumericAddress", String.class);
} catch (final NoSuchMethodException e) { } catch (final Exception ignored) {
throw new RuntimeException(e);
} }
return PARSER_METHOD; PARSER_METHOD = m;
} }
private InetAddresses() { private InetAddresses() { }
// Prevent instantiation.
}
/** /**
* Parses a numeric IPv4 or IPv6 address without performing any DNS lookups. * Parses a numeric IPv4 or IPv6 address without performing any DNS lookups.
@ -46,19 +45,28 @@ public final class InetAddresses {
if (address.isEmpty()) if (address.isEmpty())
throw new ParseException(InetAddress.class, address, "Empty address"); throw new ParseException(InetAddress.class, address, "Empty address");
try { try {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
return (InetAddress) getParserMethod().invoke(null, address);
else
return android.net.InetAddresses.parseNumericAddress(address); return android.net.InetAddresses.parseNumericAddress(address);
} catch (final IllegalAccessException | InvocationTargetException e) { else if (PARSER_METHOD != null)
return (InetAddress) PARSER_METHOD.invoke(null, address);
else
throw new NoSuchMethodException("parseNumericAddress");
} catch (final IllegalArgumentException e) {
throw new ParseException(InetAddress.class, address, e);
} catch (final Exception e) {
final Throwable cause = e.getCause(); final Throwable cause = e.getCause();
// Re-throw parsing exceptions with the original type, as callers might try to catch // Re-throw parsing exceptions with the original type, as callers might try to catch
// them. On the other hand, callers cannot be expected to handle reflection failures. // them. On the other hand, callers cannot be expected to handle reflection failures.
if (cause instanceof IllegalArgumentException) if (cause instanceof IllegalArgumentException)
throw new ParseException(InetAddress.class, address, cause); throw new ParseException(InetAddress.class, address, cause);
throw new RuntimeException(e); try {
} catch (final IllegalArgumentException e) { if (WONT_TOUCH_RESOLVER.matcher(address).matches())
throw new ParseException(InetAddress.class, address, e); return InetAddress.getByName(address);
else
throw new ParseException(InetAddress.class, address, "Not an IP address");
} catch (final UnknownHostException f) {
throw new ParseException(InetAddress.class, address, f);
}
} }
} }
} }