fix(arc_dns_injector): Fix Java 21

CachedAddresses no longer exists, so we use CachedLookup instead since
it's the same class, just renamed.

This is horrible but it works so don't blame me
This commit is contained in:
alexytomi 2025-06-24 17:38:01 +08:00
parent 66db228605
commit 2016eba00f
2 changed files with 158 additions and 6 deletions

View File

@ -5,16 +5,23 @@ public class ArcDNSInjectorAgent {
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");
String[] injectedIps = new String[]{args};
try {
CacheUtil_J9.setInetAddressCache("s.optifine.net", injectedIps, CacheUtilCommons.NEVER_EXPIRATION);
CacheUtil_J21.setInetAddressCache("s.optifine.net", injectedIps, CacheUtilCommons.NEVER_EXPIRATION);
} catch (Exception e) {
try {
CacheUtil_J8.setInetAddressCache("s.optifine.net", injectedIps, CacheUtilCommons.NEVER_EXPIRATION);
CacheUtil_J9.setInetAddressCache("s.optifine.net", injectedIps, CacheUtilCommons.NEVER_EXPIRATION);
} catch (Exception e2) {
System.out.println("Failed to inject cache!");
e2.addSuppressed(e);
e2.printStackTrace();
return;
try {
CacheUtil_J8.setInetAddressCache("s.optifine.net", injectedIps, CacheUtilCommons.NEVER_EXPIRATION);
} catch (Exception e3) {
System.out.println("Failed to inject cache!");
e2.addSuppressed(e);
e2.printStackTrace();
e3.addSuppressed(e);
e3.printStackTrace();
return;
}
}
}
System.out.println("Added DNS cache entry: s.optifine.net/"+args);

View File

@ -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_J21 {
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<Object> iterator = getExpirySetOfInetAddress().iterator(); iterator.hasNext(); ) {
Object cachedAddresses = iterator.next();
if (getHostOfInetAddress$CacheAddress(cachedAddresses).equals(host)) {
iterator.remove();
}
}
}
private static volatile Field hostFieldOfInetAddress$CacheAddress = null;
private static String getHostOfInetAddress$CacheAddress(Object cachedAddresses)
throws NoSuchFieldException, IllegalAccessException {
if (hostFieldOfInetAddress$CacheAddress == null) {
synchronized (CacheUtil_J21.class) {
if (hostFieldOfInetAddress$CacheAddress == null) { // double check
final Field f = cachedAddresses.getClass().getDeclaredField("host");
f.setAccessible(true);
hostFieldOfInetAddress$CacheAddress = f;
}
}
}
return (String) hostFieldOfInetAddress$CacheAddress.get(cachedAddresses);
}
//////////////////////////////////////////////////////////////////////////////
// getters of static cache related fields of InetAddress
//////////////////////////////////////////////////////////////////////////////
@SuppressWarnings("unchecked")
private static ConcurrentMap<String, Object> getCacheOfInetAddress()
throws NoSuchFieldException, IllegalAccessException {
return (ConcurrentMap<String, Object>) getCacheAndExpirySetOfInetAddress0()[0];
}
@SuppressWarnings("unchecked")
private static ConcurrentSkipListSet<Object> getExpirySetOfInetAddress()
throws NoSuchFieldException, IllegalAccessException {
return (ConcurrentSkipListSet<Object>) getCacheAndExpirySetOfInetAddress0()[1];
}
private static volatile Object[] ADDRESS_CACHE_AND_EXPIRY_SET = null;
private static Object[] getCacheAndExpirySetOfInetAddress0()
throws NoSuchFieldException, IllegalAccessException {
if (ADDRESS_CACHE_AND_EXPIRY_SET != null) return ADDRESS_CACHE_AND_EXPIRY_SET;
synchronized (CacheUtil_J21.class) {
if (ADDRESS_CACHE_AND_EXPIRY_SET != null) return ADDRESS_CACHE_AND_EXPIRY_SET;
final Field cacheField = InetAddress.class.getDeclaredField("cache");
cacheField.setAccessible(true);
final Field expirySetField = InetAddress.class.getDeclaredField("expirySet");
expirySetField.setAccessible(true);
ADDRESS_CACHE_AND_EXPIRY_SET = new Object[]{
cacheField.get(InetAddress.class),
expirySetField.get(InetAddress.class)
};
return ADDRESS_CACHE_AND_EXPIRY_SET;
}
}
//////////////////////////////////////////////////////////////////////////////
private static final String inetAddress$CachedAddresses_ClassName = "java.net.InetAddress$CachedLookup";
public static void clearInetAddressCache() throws NoSuchFieldException, IllegalAccessException {
getCacheOfInetAddress().clear();
getExpirySetOfInetAddress().clear();
}
private CacheUtil_J21() {
}
}