From 0b4d775a2146c8772ad2cb3f631f7ecbdab0a686 Mon Sep 17 00:00:00 2001
From: ArtDev <45949002+artdeell@users.noreply.github.com>
Date: Sun, 20 Feb 2022 21:12:36 +0300
Subject: [PATCH] Upstreamify profiles (#2765)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* add Arc capes DNS injector
* Bug fix: Arc DNS injector breaks on Java 17
Error:
Failed to inject cache!
java.lang.reflect.InaccessibleObjectException: Unable to make java.net.InetAddress$CachedAddresses(java.lang.String,java.net.InetAddress[],long) accessible: module java.base does not "opens java.net" to unnamed module @4157f54e
* Validate assets even if it’s fully downloaded (#2730)
* Update MinecraftDownloaderTask.java
Co-authored-by: Duy Tran Khanh <40482367+khanhduytran0@users.noreply.github.com>
---
.../src/main/assets/arc_dns_injector.jar | Bin 0 -> 13243 bytes
.../kdt/pojavlaunch/PojavLoginActivity.java | 1 +
.../main/java/net/kdt/pojavlaunch/Tools.java | 3 +
.../prefs/LauncherPreferences.java | 2 +
.../tasks/MinecraftDownloaderTask.java | 8 +-
.../net/kdt/pojavlaunch/utils/JREUtils.java | 8 +-
.../src/main/res/values/strings.xml | 2 +-
.../src/main/res/xml/pref_misc.xml | 5 +
arc_dns_injector/.gitignore | 1 +
arc_dns_injector/build.gradle | 15 +
.../artdeell/arcdns/ArcDNSInjectorAgent.java | 20 +
.../git/artdeell/arcdns/CacheUtilCommons.java | 324 ++++++++++++++++
.../git/artdeell/arcdns/CacheUtil_J8.java | 153 ++++++++
.../git/artdeell/arcdns/CacheUtil_J9.java | 145 +++++++
.../artdeell/arcdns/other/JavaVersion.java | 366 ++++++++++++++++++
settings.gradle | 1 +
16 files changed, 1047 insertions(+), 7 deletions(-)
create mode 100644 app_pojavlauncher/src/main/assets/arc_dns_injector.jar
create mode 100644 arc_dns_injector/.gitignore
create mode 100644 arc_dns_injector/build.gradle
create mode 100644 arc_dns_injector/src/main/java/git/artdeell/arcdns/ArcDNSInjectorAgent.java
create mode 100644 arc_dns_injector/src/main/java/git/artdeell/arcdns/CacheUtilCommons.java
create mode 100644 arc_dns_injector/src/main/java/git/artdeell/arcdns/CacheUtil_J8.java
create mode 100644 arc_dns_injector/src/main/java/git/artdeell/arcdns/CacheUtil_J9.java
create mode 100644 arc_dns_injector/src/main/java/git/artdeell/arcdns/other/JavaVersion.java
diff --git a/app_pojavlauncher/src/main/assets/arc_dns_injector.jar b/app_pojavlauncher/src/main/assets/arc_dns_injector.jar
new file mode 100644
index 0000000000000000000000000000000000000000..3c9ddd6bf377c3efdb4f9439231f654c2b9a5332
GIT binary patch
literal 13243
zcma*O1yEeiwmnR64esvl?(XgmK?V!1gC)4Tdmy;GTX1&^4uiXEkT0ow-<99H_x-
eX20*|+xK
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
XJk;-8BN!OM?~CGh=Fy+!&!_(n&s|-S
literal 0
HcmV?d00001
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavLoginActivity.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavLoginActivity.java
index 7f71feffe..4366ae75c 100644
--- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavLoginActivity.java
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavLoginActivity.java
@@ -340,6 +340,7 @@ public class PojavLoginActivity extends BaseActivity
// TODO: Remove after implement.
Tools.copyAssetFile(this, "launcher_profiles.json", Tools.DIR_GAME_NEW, false);
Tools.copyAssetFile(this,"resolv.conf",Tools.DIR_DATA, true);
+ Tools.copyAssetFile(this,"arc_dns_injector.jar",Tools.DIR_DATA, true);
AssetManager am = this.getAssets();
unpackComponent(am, "caciocavallo");
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java
index 5f324d306..78007b76a 100644
--- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java
@@ -150,6 +150,9 @@ public final class Tools {
// Only Java 8 supports headful AWT for now
if (JREUtils.jreReleaseList.get("JAVA_VERSION").equals("1.8.0")) {
getCacioJavaArgs(javaArgList, false);
+ } else if (LauncherPreferences.PREF_ARC_CAPES) {
+ // Opens the java.net package to Arc DNS injector on Java 9+
+ javaArgList.add("--add-opens=java.base/java.net=ALL-UNNAMED");
}
/*
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java
index aff6d5e4b..16013bfe6 100644
--- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java
@@ -39,6 +39,7 @@ public class LauncherPreferences
public static boolean PREF_VBO_DISABLE_HACK = false;
public static boolean PREF_VIRTUAL_MOUSE_START = false;
public static boolean PREF_OPENGL_VERSION_HACK = false;
+ public static boolean PREF_ARC_CAPES = false;
public static void loadPreferences(Context ctx) {
@@ -73,6 +74,7 @@ public class LauncherPreferences
PREF_ENABLE_PROFILES = DEFAULT_PREF.getBoolean("enable_profiles", false);
PREF_VIRTUAL_MOUSE_START = DEFAULT_PREF.getBoolean("mouse_start", false);
PREF_OPENGL_VERSION_HACK = DEFAULT_PREF.getBoolean("gles_version_hack", false);
+ PREF_ARC_CAPES = DEFAULT_PREF.getBoolean("arc_capes",false);
/*
if (PREF_CUSTOM_JAVA_ARGS.isEmpty()) {
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/MinecraftDownloaderTask.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/MinecraftDownloaderTask.java
index b41f9bda7..60aeb66dc 100644
--- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/MinecraftDownloaderTask.java
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/MinecraftDownloaderTask.java
@@ -452,8 +452,8 @@ public class MinecraftDownloaderTask extends AsyncTask workQueue = new LinkedBlockingQueue<>();
final ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 500, TimeUnit.MILLISECONDS, workQueue);
mActivity.mIsAssetsProcessing = true;
- File hasDownloadedFile = new File(outputDir, "downloaded/" + assetsVersion + ".downloaded");
- if (!hasDownloadedFile.exists()) {
+ //File hasDownloadedFile = new File(outputDir, "downloaded/" + assetsVersion + ".downloaded");
+ if (true) { //(!hasDownloadedFile.exists()) {
System.out.println("Assets begin time: " + System.currentTimeMillis());
Map assetsObjects = assets.objects;
int assetsSizeBytes=0;
@@ -501,8 +501,8 @@ public class MinecraftDownloaderTask extends AsyncTask userArguments = parseJavaArguments(LauncherPreferences.PREF_CUSTOM_JAVA_ARGS);
String resolvFile;
resolvFile = new File(Tools.DIR_DATA,"resolv.conf").getAbsolutePath();
- String[] overridableArguments = new String[]{
+
+ ArrayList overridableArguments = new ArrayList<>(Arrays.asList(
"-Djava.home=" + Tools.DIR_HOME_JRE,
"-Djava.io.tmpdir=" + ctx.getCacheDir().getAbsolutePath(),
"-Duser.home=" + new File(Tools.DIR_GAME_NEW).getParent(),
@@ -366,7 +367,10 @@ public class JREUtils {
"-Dnet.minecraft.clientmodname=" + Tools.APP_NAME,
"-Dfml.earlyprogresswindow=false" //Forge 1.14+ workaround
- };
+ ));
+ if(LauncherPreferences.PREF_ARC_CAPES) {
+ overridableArguments.add("-javaagent:"+new File(Tools.DIR_DATA,"arc_dns_injector.jar").getAbsolutePath()+"=23.95.137.176");
+ }
List additionalArguments = new ArrayList<>();
for(String arg : overridableArguments) {
String strippedArg = arg.substring(0,arg.indexOf('='));
diff --git a/app_pojavlauncher/src/main/res/values/strings.xml b/app_pojavlauncher/src/main/res/values/strings.xml
index 7e8640aeb..c61c03b47 100644
--- a/app_pojavlauncher/src/main/res/values/strings.xml
+++ b/app_pojavlauncher/src/main/res/values/strings.xml
@@ -302,5 +302,5 @@
Force openGL 1
Help with compatibility on some old versions
Arc Capes
- Enables capes from Arc. For more information please visit https://arccapes.com
+ Enables capes from Arc. For more information please visit https://arccapes.com. Requires OptiFine.
diff --git a/app_pojavlauncher/src/main/res/xml/pref_misc.xml b/app_pojavlauncher/src/main/res/xml/pref_misc.xml
index dff30194a..bb241cfbf 100644
--- a/app_pojavlauncher/src/main/res/xml/pref_misc.xml
+++ b/app_pojavlauncher/src/main/res/xml/pref_misc.xml
@@ -26,6 +26,11 @@
android:key="checkLibraries"
android:summary="@string/mcl_setting_check_libraries_subtitle"
android:title="@string/mcl_setting_check_libraries" />
+
diff --git a/arc_dns_injector/.gitignore b/arc_dns_injector/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/arc_dns_injector/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/arc_dns_injector/build.gradle b/arc_dns_injector/build.gradle
new file mode 100644
index 000000000..85e789bf6
--- /dev/null
+++ b/arc_dns_injector/build.gradle
@@ -0,0 +1,15 @@
+plugins {
+ id 'java-library'
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_1_7
+ targetCompatibility = JavaVersion.VERSION_1_7
+}
+jar {
+ manifest {
+ attributes("Manifest-Version": "1.0",
+ "PreMain-Class": "git.artdeell.arcdns.ArcDNSInjectorAgent")
+ }
+ destinationDirectory.set(file("../app_pojavlauncher/src/main/assets/"))
+}
\ No newline at end of file
diff --git a/arc_dns_injector/src/main/java/git/artdeell/arcdns/ArcDNSInjectorAgent.java b/arc_dns_injector/src/main/java/git/artdeell/arcdns/ArcDNSInjectorAgent.java
new file mode 100644
index 000000000..70fbb05fa
--- /dev/null
+++ b/arc_dns_injector/src/main/java/git/artdeell/arcdns/ArcDNSInjectorAgent.java
@@ -0,0 +1,20 @@
+package git.artdeell.arcdns;
+
+public class ArcDNSInjectorAgent {
+ public static void premain(String args) {
+ System.out.println("Arc Capes DNS Injector");
+ System.out.println("Parts of Alibaba's DCM library were used, please read https://github.com/alibaba/java-dns-cache-manipulator/blob/main/README.md for more info");
+ try {
+ String[] injectedIps = new String[]{args};
+ if (CacheUtilCommons.isJavaVersionAtMost8()) {
+ CacheUtil_J8.setInetAddressCache("s.optifine.net", injectedIps, CacheUtilCommons.NEVER_EXPIRATION);
+ } else {
+ CacheUtil_J9.setInetAddressCache("s.optifine.net", injectedIps, CacheUtilCommons.NEVER_EXPIRATION);
+ }
+ System.out.println("Added DNS cache entry: s.optifine.net/"+args);
+ }catch (Exception e) {
+ System.out.println("Failed to inject cache!");
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/arc_dns_injector/src/main/java/git/artdeell/arcdns/CacheUtilCommons.java b/arc_dns_injector/src/main/java/git/artdeell/arcdns/CacheUtilCommons.java
new file mode 100644
index 000000000..5de79fb24
--- /dev/null
+++ b/arc_dns_injector/src/main/java/git/artdeell/arcdns/CacheUtilCommons.java
@@ -0,0 +1,324 @@
+package git.artdeell.arcdns;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import git.artdeell.arcdns.other.JavaVersion;
+
+public class CacheUtilCommons {
+ public static final long NEVER_EXPIRATION = Long.MAX_VALUE;
+ static InetAddress[] toInetAddressArray(String host, String[] ips) throws UnknownHostException {
+ InetAddress[] addresses = new InetAddress[ips.length];
+ for (int i = 0; i < addresses.length; i++) {
+ addresses[i] = InetAddress.getByAddress(host, ip2ByteArray(ips[i]));
+ }
+ return addresses;
+ }
+ private static final String INVALID_IP_V6_ADDRESS = ": invalid IPv6 address";
+ private static final String INVALID_IP_ADDRESS = ": invalid IP address";
+
+ static byte[] ip2ByteArray(String ip) {
+ boolean ipv6Expected = false;
+ if (ip.charAt(0) == '[') {
+ // This is supposed to be an IPv6 literal
+ if (ip.length() > 2 && ip.charAt(ip.length() - 1) == ']') {
+ ip = ip.substring(1, ip.length() - 1);
+ ipv6Expected = true;
+ } else {
+ // This was supposed to be a IPv6 address, but it's not!
+ throw new IllegalArgumentException(ip + INVALID_IP_V6_ADDRESS);
+ }
+ }
+
+ if (Character.digit(ip.charAt(0), 16) != -1 || (ip.charAt(0) == ':')) {
+ // see if it is IPv4 address
+ byte[] address = textToNumericFormatV4(ip);
+ if (address != null) return address;
+
+ // see if it is IPv6 address
+ // Check if a numeric or string zone id is present
+ address = textToNumericFormatV6(ip);
+ if (address != null) return address;
+
+ if (ipv6Expected) {
+ throw new IllegalArgumentException(ip + INVALID_IP_V6_ADDRESS);
+ } else {
+ throw new IllegalArgumentException(ip + INVALID_IP_ADDRESS);
+ }
+ } else {
+ throw new IllegalArgumentException(ip + INVALID_IP_ADDRESS);
+ }
+ }
+ private static final int INADDR4SZ = 4;
+ private static final int INADDR16SZ = 16;
+ private static final int INT16SZ = 2;
+
+ /*
+ * Converts IPv4 address in its textual presentation form
+ * into its numeric binary form.
+ *
+ * @param src a String representing an IPv4 address in standard format
+ * @return a byte array representing the IPv4 numeric address
+ */
+ @SuppressWarnings("fallthrough")
+ static byte[] textToNumericFormatV4(String src)
+ {
+ byte[] res = new byte[INADDR4SZ];
+
+ long tmpValue = 0;
+ int currByte = 0;
+ boolean newOctet = true;
+
+ int len = src.length();
+ if (len == 0 || len > 15) {
+ return null;
+ }
+ /*
+ * When only one part is given, the value is stored directly in
+ * the network address without any byte rearrangement.
+ *
+ * When a two part address is supplied, the last part is
+ * interpreted as a 24-bit quantity and placed in the right
+ * most three bytes of the network address. This makes the
+ * two part address format convenient for specifying Class A
+ * network addresses as net.host.
+ *
+ * When a three part address is specified, the last part is
+ * interpreted as a 16-bit quantity and placed in the right
+ * most two bytes of the network address. This makes the
+ * three part address format convenient for specifying
+ * Class B net- work addresses as 128.net.host.
+ *
+ * When four parts are specified, each is interpreted as a
+ * byte of data and assigned, from left to right, to the
+ * four bytes of an IPv4 address.
+ *
+ * We determine and parse the leading parts, if any, as single
+ * byte values in one pass directly into the resulting byte[],
+ * then the remainder is treated as a 8-to-32-bit entity and
+ * translated into the remaining bytes in the array.
+ */
+ for (int i = 0; i < len; i++) {
+ char c = src.charAt(i);
+ if (c == '.') {
+ if (newOctet || tmpValue < 0 || tmpValue > 0xff || currByte == 3) {
+ return null;
+ }
+ res[currByte++] = (byte) (tmpValue & 0xff);
+ tmpValue = 0;
+ newOctet = true;
+ } else {
+ int digit = Character.digit(c, 10);
+ if (digit < 0) {
+ return null;
+ }
+ tmpValue *= 10;
+ tmpValue += digit;
+ newOctet = false;
+ }
+ }
+ if (newOctet || tmpValue < 0 || tmpValue >= (1L << ((4 - currByte) * 8))) {
+ return null;
+ }
+ switch (currByte) {
+ case 0:
+ res[0] = (byte) ((tmpValue >> 24) & 0xff);
+ case 1:
+ res[1] = (byte) ((tmpValue >> 16) & 0xff);
+ case 2:
+ res[2] = (byte) ((tmpValue >> 8) & 0xff);
+ case 3:
+ res[3] = (byte) ((tmpValue >> 0) & 0xff);
+ }
+ return res;
+ }
+
+ /*
+ * Convert IPv6 presentation level address to network order binary form.
+ * credit:
+ * Converted from C code from Solaris 8 (inet_pton)
+ *
+ * Any component of the string following a per-cent % is ignored.
+ *
+ * @param src a String representing an IPv6 address in textual format
+ * @return a byte array representing the IPv6 numeric address
+ */
+ static byte[] textToNumericFormatV6(String src)
+ {
+ // Shortest valid string is "::", hence at least 2 chars
+ if (src.length() < 2) {
+ return null;
+ }
+
+ int colonp;
+ char ch;
+ boolean saw_xdigit;
+ int val;
+ char[] srcb = src.toCharArray();
+ byte[] dst = new byte[INADDR16SZ];
+
+ int srcb_length = srcb.length;
+ int pc = src.indexOf ('%');
+ if (pc == srcb_length -1) {
+ return null;
+ }
+
+ if (pc != -1) {
+ srcb_length = pc;
+ }
+
+ colonp = -1;
+ int i = 0, j = 0;
+ /* Leading :: requires some special handling. */
+ if (srcb[i] == ':')
+ if (srcb[++i] != ':')
+ return null;
+ int curtok = i;
+ saw_xdigit = false;
+ val = 0;
+ while (i < srcb_length) {
+ ch = srcb[i++];
+ int chval = Character.digit(ch, 16);
+ if (chval != -1) {
+ val <<= 4;
+ val |= chval;
+ if (val > 0xffff)
+ return null;
+ saw_xdigit = true;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = i;
+ if (!saw_xdigit) {
+ if (colonp != -1)
+ return null;
+ colonp = j;
+ continue;
+ } else if (i == srcb_length) {
+ return null;
+ }
+ if (j + INT16SZ > INADDR16SZ)
+ return null;
+ dst[j++] = (byte) ((val >> 8) & 0xff);
+ dst[j++] = (byte) (val & 0xff);
+ saw_xdigit = false;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((j + INADDR4SZ) <= INADDR16SZ)) {
+ String ia4 = src.substring(curtok, srcb_length);
+ /* check this IPv4 address has 3 dots, ie. A.B.C.D */
+ int dot_count = 0, index=0;
+ while ((index = ia4.indexOf ('.', index)) != -1) {
+ dot_count ++;
+ index ++;
+ }
+ if (dot_count != 3) {
+ return null;
+ }
+ byte[] v4addr = textToNumericFormatV4(ia4);
+ if (v4addr == null) {
+ return null;
+ }
+ for (int k = 0; k < INADDR4SZ; k++) {
+ dst[j++] = v4addr[k];
+ }
+ saw_xdigit = false;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return null;
+ }
+ if (saw_xdigit) {
+ if (j + INT16SZ > INADDR16SZ)
+ return null;
+ dst[j++] = (byte) ((val >> 8) & 0xff);
+ dst[j++] = (byte) (val & 0xff);
+ }
+
+ if (colonp != -1) {
+ int n = j - colonp;
+
+ if (j == INADDR16SZ)
+ return null;
+ for (i = 1; i <= n; i++) {
+ dst[INADDR16SZ - i] = dst[colonp + n - i];
+ dst[colonp + n - i] = 0;
+ }
+ j = INADDR16SZ;
+ }
+ if (j != INADDR16SZ)
+ return null;
+ byte[] newdst = convertFromIPv4MappedAddress(dst);
+ if (newdst != null) {
+ return newdst;
+ } else {
+ return dst;
+ }
+ }
+
+ /*
+ * Convert IPv4-Mapped address to IPv4 address. Both input and
+ * returned value are in network order binary form.
+ *
+ * @param src a String representing an IPv4-Mapped address in textual format
+ * @return a byte array representing the IPv4 numeric address
+ */
+ private static byte[] convertFromIPv4MappedAddress(byte[] addr) {
+ if (isIPv4MappedAddress(addr)) {
+ byte[] newAddr = new byte[INADDR4SZ];
+ System.arraycopy(addr, 12, newAddr, 0, INADDR4SZ);
+ return newAddr;
+ }
+ return null;
+ }
+
+ /**
+ * Utility routine to check if the InetAddress is an
+ * IPv4 mapped IPv6 address.
+ *
+ * @return a boolean
indicating if the InetAddress is
+ * an IPv4 mapped IPv6 address; or false if address is IPv4 address.
+ */
+ private static boolean isIPv4MappedAddress(byte[] addr) {
+ if (addr.length < INADDR16SZ) {
+ return false;
+ }
+ if ((addr[0] == 0x00) && (addr[1] == 0x00) &&
+ (addr[2] == 0x00) && (addr[3] == 0x00) &&
+ (addr[4] == 0x00) && (addr[5] == 0x00) &&
+ (addr[6] == 0x00) && (addr[7] == 0x00) &&
+ (addr[8] == 0x00) && (addr[9] == 0x00) &&
+ (addr[10] == (byte)0xff) &&
+ (addr[11] == (byte)0xff)) {
+ return true;
+ }
+ return false;
+ }
+ public static boolean isJavaVersionAtMost8() {
+ return JAVA_SPECIFICATION_VERSION_AS_ENUM.atMost(JavaVersion.JAVA_1_8);
+ }
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // Below source code is copied from commons-lang-3.12.0:
+ //
+ // https://github.com/apache/commons-lang/blob/rel/commons-lang-3.12.0/src/main/java/org/apache/commons/lang3/SystemUtils.java
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+ private static final String JAVA_SPECIFICATION_VERSION = getSystemProperty("java.specification.version");
+ private static final JavaVersion JAVA_SPECIFICATION_VERSION_AS_ENUM = JavaVersion.get(JAVA_SPECIFICATION_VERSION);
+
+ @SuppressWarnings({"CommentedOutCode", "SameParameterValue"})
+ private static String getSystemProperty(final String property) {
+ try {
+ return System.getProperty(property);
+ } catch (final SecurityException ex) {
+ // we are not allowed to look at this property
+ // System.err.println("Caught a SecurityException reading the system property '" + property
+ // + "'; the SystemUtils property value will default to null.");
+ return null;
+ }
+ }
+
+}
diff --git a/arc_dns_injector/src/main/java/git/artdeell/arcdns/CacheUtil_J8.java b/arc_dns_injector/src/main/java/git/artdeell/arcdns/CacheUtil_J8.java
new file mode 100644
index 000000000..7c53da9be
--- /dev/null
+++ b/arc_dns_injector/src/main/java/git/artdeell/arcdns/CacheUtil_J8.java
@@ -0,0 +1,153 @@
+package git.artdeell.arcdns;
+
+import static git.artdeell.arcdns.CacheUtilCommons.NEVER_EXPIRATION;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Map;
+
+
+public final class CacheUtil_J8 {
+
+ public static void setInetAddressCache(String host, String[] ips, long expireMillis)
+ throws UnknownHostException, IllegalAccessException, InstantiationException,
+ InvocationTargetException, ClassNotFoundException, NoSuchFieldException {
+ host = host.toLowerCase();
+ long expiration = expireMillis == NEVER_EXPIRATION ? NEVER_EXPIRATION : System.currentTimeMillis() + expireMillis;
+ Object entry = newCacheEntry(host, ips, expiration);
+
+ synchronized (getAddressCacheOfInetAddress()) {
+ getCache().put(host, entry);
+ getNegativeCache().remove(host);
+ }
+ }
+
+ private static Object newCacheEntry(String host, String[] ips, long expiration)
+ throws UnknownHostException, ClassNotFoundException, IllegalAccessException,
+ InvocationTargetException, InstantiationException {
+ // InetAddress.CacheEntry has only one constructor
+ return getConstructorOfInetAddress$CacheEntry().newInstance(CacheUtilCommons.toInetAddressArray(host, ips), expiration);
+ }
+
+ private static volatile Constructor> constructorOfInetAddress$CacheEntry = null;
+
+ private static Constructor> getConstructorOfInetAddress$CacheEntry() throws ClassNotFoundException {
+ if (constructorOfInetAddress$CacheEntry != null) return constructorOfInetAddress$CacheEntry;
+
+ synchronized (CacheUtilCommons.class) {
+ // double check
+ if (constructorOfInetAddress$CacheEntry != null) return constructorOfInetAddress$CacheEntry;
+
+ final String className = "java.net.InetAddress$CacheEntry";
+ final Class> clazz = Class.forName(className);
+
+ // InetAddress.CacheEntry has only one constructor:
+ // - for jdk 6, constructor signature is CacheEntry(Object address, long expiration)
+ // - for jdk 7/8, constructor signature is CacheEntry(InetAddress[] addresses, long expiration)
+ //
+ // code in jdk 6:
+ // https://hg.openjdk.java.net/jdk6/jdk6/jdk/file/8deef18bb749/src/share/classes/java/net/InetAddress.java#l739
+ // code in jdk 7:
+ // https://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/4dd5e486620d/src/share/classes/java/net/InetAddress.java#l742
+ // code in jdk 8:
+ // https://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/45e4e636b757/src/share/classes/java/net/InetAddress.java#l748
+ final Constructor> constructor = clazz.getDeclaredConstructors()[0];
+ constructor.setAccessible(true);
+
+ constructorOfInetAddress$CacheEntry = constructor;
+ return constructor;
+ }
+ }
+
+ public static void removeInetAddressCache(String host)
+ throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
+ host = host.toLowerCase();
+
+ synchronized (getAddressCacheOfInetAddress()) {
+ getCache().remove(host);
+ getNegativeCache().remove(host);
+ }
+ }
+
+ private static Map getCache()
+ throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
+ return getCacheOfInetAddress$Cache0(getAddressCacheOfInetAddress());
+ }
+
+ private static Map getNegativeCache()
+ throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
+ return getCacheOfInetAddress$Cache0(getNegativeCacheOfInetAddress());
+ }
+
+
+ private static volatile Field cacheMapFieldOfInetAddress$Cache = null;
+
+ @SuppressWarnings("unchecked")
+ private static Map getCacheOfInetAddress$Cache0(Object inetAddressCache)
+ throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
+ if (cacheMapFieldOfInetAddress$Cache == null) {
+ synchronized (CacheUtil_J8.class) {
+ if (cacheMapFieldOfInetAddress$Cache == null) { // double check
+ final Class> clazz = Class.forName("java.net.InetAddress$Cache");
+ final Field f = clazz.getDeclaredField("cache");
+ f.setAccessible(true);
+ cacheMapFieldOfInetAddress$Cache = f;
+ }
+ }
+ }
+
+ return (Map) cacheMapFieldOfInetAddress$Cache.get(inetAddressCache);
+ }
+
+ private static Object getAddressCacheOfInetAddress()
+ throws NoSuchFieldException, IllegalAccessException {
+ return getAddressCacheAndNegativeCacheOfInetAddress0()[0];
+ }
+
+ private static Object getNegativeCacheOfInetAddress()
+ throws NoSuchFieldException, IllegalAccessException {
+ return getAddressCacheAndNegativeCacheOfInetAddress0()[1];
+ }
+
+ private static volatile Object[] ADDRESS_CACHE_AND_NEGATIVE_CACHE = null;
+
+ private static Object[] getAddressCacheAndNegativeCacheOfInetAddress0()
+ throws NoSuchFieldException, IllegalAccessException {
+ if (ADDRESS_CACHE_AND_NEGATIVE_CACHE != null) return ADDRESS_CACHE_AND_NEGATIVE_CACHE;
+
+ synchronized (CacheUtil_J8.class) {
+ // double check
+ if (ADDRESS_CACHE_AND_NEGATIVE_CACHE != null) return ADDRESS_CACHE_AND_NEGATIVE_CACHE;
+
+ final Field cacheField = InetAddress.class.getDeclaredField("addressCache");
+ cacheField.setAccessible(true);
+
+ final Field negativeCacheField = InetAddress.class.getDeclaredField("negativeCache");
+ negativeCacheField.setAccessible(true);
+
+ ADDRESS_CACHE_AND_NEGATIVE_CACHE = new Object[]{
+ cacheField.get(InetAddress.class),
+ negativeCacheField.get(InetAddress.class)
+ };
+ return ADDRESS_CACHE_AND_NEGATIVE_CACHE;
+ }
+ }
+
+ private static boolean isDnsCacheEntryExpired(String host) {
+ return null == host || "0.0.0.0".equals(host);
+ }
+
+ public static void clearInetAddressCache()
+ throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
+ synchronized (getAddressCacheOfInetAddress()) {
+ getCache().clear();
+ getNegativeCache().clear();
+ }
+ }
+
+ private CacheUtil_J8() {
+ }
+}
diff --git a/arc_dns_injector/src/main/java/git/artdeell/arcdns/CacheUtil_J9.java b/arc_dns_injector/src/main/java/git/artdeell/arcdns/CacheUtil_J9.java
new file mode 100644
index 000000000..b54060bae
--- /dev/null
+++ b/arc_dns_injector/src/main/java/git/artdeell/arcdns/CacheUtil_J9.java
@@ -0,0 +1,145 @@
+package git.artdeell.arcdns;
+import static git.artdeell.arcdns.CacheUtilCommons.NEVER_EXPIRATION;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+public class CacheUtil_J9 {
+ public static void setInetAddressCache(String host, String[] ips, long expireMillis)
+ throws UnknownHostException, IllegalAccessException, InstantiationException,
+ InvocationTargetException, ClassNotFoundException, NoSuchFieldException {
+ long expiration = expireMillis == NEVER_EXPIRATION ? NEVER_EXPIRATION : System.nanoTime() + expireMillis * 1_000_000;
+ Object cachedAddresses = newCachedAddresses(host, ips, expiration);
+
+ getCacheOfInetAddress().put(host, cachedAddresses);
+ getExpirySetOfInetAddress().add(cachedAddresses);
+ }
+
+ private static Object newCachedAddresses(String host, String[] ips, long expiration)
+ throws ClassNotFoundException, UnknownHostException, IllegalAccessException,
+ InvocationTargetException, InstantiationException {
+ // InetAddress.CachedAddresses has only one constructor
+ return getConstructorOfInetAddress$CachedAddresses().newInstance(host, CacheUtilCommons.toInetAddressArray(host, ips), expiration);
+ }
+
+ private static volatile Constructor> constructorOfInetAddress$CachedAddresses = null;
+
+ private static Constructor> getConstructorOfInetAddress$CachedAddresses() throws ClassNotFoundException {
+ if (constructorOfInetAddress$CachedAddresses != null) return constructorOfInetAddress$CachedAddresses;
+
+ synchronized (CacheUtilCommons.class) {
+ // double check
+ if (constructorOfInetAddress$CachedAddresses != null) return constructorOfInetAddress$CachedAddresses;
+
+ final Class> clazz = Class.forName(inetAddress$CachedAddresses_ClassName);
+
+ // InetAddress.CacheEntry has only one constructor:
+ //
+ // - for jdk 9-jdk12, constructor signature is CachedAddresses(String host, InetAddress[] inetAddresses, long expiryTime)
+ // code in jdk 9:
+ // https://hg.openjdk.java.net/jdk9/jdk9/jdk/file/65464a307408/src/java.base/share/classes/java/net/InetAddress.java#l783
+ // code in jdk 11:
+ // https://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/java.base/share/classes/java/net/InetAddress.java#l787
+ final Constructor> constructor = clazz.getDeclaredConstructors()[0];
+ constructor.setAccessible(true);
+
+ constructorOfInetAddress$CachedAddresses = constructor;
+ return constructor;
+ }
+ }
+
+ public static void removeInetAddressCache(String host) throws NoSuchFieldException, IllegalAccessException {
+ getCacheOfInetAddress().remove(host);
+ removeHostFromExpirySetOfInetAddress(host);
+ }
+
+ /**
+ * @see #getExpirySetOfInetAddress()
+ */
+ private static void removeHostFromExpirySetOfInetAddress(String host)
+ throws NoSuchFieldException, IllegalAccessException {
+ for (Iterator