Use MacOSDnsServerAddressStreamProvider when on the classpath and we … (#10079)
Motivation:
939e928312
introduced MacOSDnsServerAddressStreamProvider which will ensure the right nameservers are selected when running on MacOS. To ensure this is done automatically on MacOS we should use it by default on these platforms.
Modifications:
Try to use MacOSDnsServerAddressStreamProvider when on MacOS via reflection and fallback if not possible
Result:
Ensure the right nameservers are used on MacOS even when a VPN (for example) is used.
This commit is contained in:
parent
c88d320230
commit
dddde43dcf
@ -42,10 +42,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
*/
|
||||
public final class MacOSDnsServerAddressStreamProvider implements DnsServerAddressStreamProvider {
|
||||
|
||||
// Fallback provider
|
||||
private static final DnsServerAddressStreamProvider DEFAULT_PROVIDER =
|
||||
DnsServerAddressStreamProviders.platformDefault();
|
||||
|
||||
private static final Throwable UNAVAILABILITY_CAUSE;
|
||||
|
||||
private static final InternalLogger logger =
|
||||
@ -113,7 +109,7 @@ public final class MacOSDnsServerAddressStreamProvider implements DnsServerAddre
|
||||
if (resolvers == null || resolvers.length == 0) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, DnsServerAddresses> resolverMap = new HashMap<String, DnsServerAddresses>(resolvers.length);
|
||||
Map<String, DnsServerAddresses> resolverMap = new HashMap<>(resolvers.length);
|
||||
for (DnsResolver resolver: resolvers) {
|
||||
// Skip mdns
|
||||
if ("mdns".equalsIgnoreCase(resolver.options())) {
|
||||
@ -167,7 +163,7 @@ public final class MacOSDnsServerAddressStreamProvider implements DnsServerAddre
|
||||
if (addresses != null) {
|
||||
return addresses.stream();
|
||||
}
|
||||
return DEFAULT_PROVIDER.nameServerAddressStream(originalHostname);
|
||||
return DnsServerAddressStreamProviders.unixDefault().nameServerAddressStream(originalHostname);
|
||||
}
|
||||
|
||||
DnsServerAddresses addresses = resolverMap.get(hostname);
|
||||
|
@ -17,6 +17,8 @@ package io.netty.resolver.dns.macos;
|
||||
|
||||
import io.netty.resolver.dns.DnsServerAddressStream;
|
||||
import io.netty.resolver.dns.DnsServerAddressStreamProvider;
|
||||
import io.netty.resolver.dns.DnsServerAddressStreamProviders;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.BeforeClass;
|
||||
@ -30,7 +32,7 @@ public class MacOSDnsServerAddressStreamProviderTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
public void testStream() {
|
||||
DnsServerAddressStreamProvider provider = new MacOSDnsServerAddressStreamProvider();
|
||||
DnsServerAddressStream stream = provider.nameServerAddressStream("netty.io");
|
||||
Assert.assertNotNull(stream);
|
||||
@ -40,4 +42,11 @@ public class MacOSDnsServerAddressStreamProviderTest {
|
||||
Assert.assertNotEquals(0, stream.next().getPort());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultUseCorrectInstance() {
|
||||
Assert.assertThat(DnsServerAddressStreamProviders.platformDefault(),
|
||||
Matchers.instanceOf(MacOSDnsServerAddressStreamProvider.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,7 +16,14 @@
|
||||
package io.netty.resolver.dns;
|
||||
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import io.netty.util.internal.logging.InternalLogger;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
@ -24,37 +31,46 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
* Utility methods related to {@link DnsServerAddressStreamProvider}.
|
||||
*/
|
||||
public final class DnsServerAddressStreamProviders {
|
||||
// We use 5 minutes which is the same as what OpenJDK is using in sun.net.dns.ResolverConfigurationImpl.
|
||||
private static final long REFRESH_INTERVAL = TimeUnit.MINUTES.toNanos(5);
|
||||
|
||||
// TODO(scott): how is this done on Windows? This may require a JNI call to GetNetworkParams
|
||||
// https://msdn.microsoft.com/en-us/library/aa365968(VS.85).aspx.
|
||||
private static final DnsServerAddressStreamProvider DEFAULT_DNS_SERVER_ADDRESS_STREAM_PROVIDER =
|
||||
new DnsServerAddressStreamProvider() {
|
||||
private volatile DnsServerAddressStreamProvider currentProvider = provider();
|
||||
private final AtomicLong lastRefresh = new AtomicLong(System.nanoTime());
|
||||
private static final InternalLogger LOGGER =
|
||||
InternalLoggerFactory.getInstance(DnsServerAddressStreamProviders.class);
|
||||
private static final Constructor<? extends DnsServerAddressStreamProvider> STREAM_PROVIDER_CONSTRUCTOR;
|
||||
|
||||
@Override
|
||||
public DnsServerAddressStream nameServerAddressStream(String hostname) {
|
||||
long last = lastRefresh.get();
|
||||
DnsServerAddressStreamProvider current = currentProvider;
|
||||
if (System.nanoTime() - last > REFRESH_INTERVAL) {
|
||||
// This is slightly racy which means it will be possible still use the old configuration for a small
|
||||
// amount of time, but that's ok.
|
||||
if (lastRefresh.compareAndSet(last, System.nanoTime())) {
|
||||
current = currentProvider = provider();
|
||||
static {
|
||||
Constructor<? extends DnsServerAddressStreamProvider> constructor = null;
|
||||
if (PlatformDependent.isOsx()) {
|
||||
try {
|
||||
// As MacOSDnsServerAddressStreamProvider is contained in another jar which depends on this jar
|
||||
// we use reflection to use it if its on the classpath.
|
||||
Object maybeProvider = AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
|
||||
try {
|
||||
return Class.forName(
|
||||
"io.netty.resolver.dns.macos.MacOSDnsServerAddressStreamProvider",
|
||||
true,
|
||||
DnsServerAddressStreamProviders.class.getClassLoader());
|
||||
} catch (Throwable cause) {
|
||||
return cause;
|
||||
}
|
||||
});
|
||||
if (maybeProvider instanceof Class) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends DnsServerAddressStreamProvider> providerClass =
|
||||
(Class<? extends DnsServerAddressStreamProvider>) maybeProvider;
|
||||
Method method = providerClass.getMethod("ensureAvailability");
|
||||
method.invoke(null);
|
||||
constructor = providerClass.getConstructor();
|
||||
constructor.newInstance();
|
||||
} else if (!(maybeProvider instanceof ClassNotFoundException)) {
|
||||
throw (Throwable) maybeProvider;
|
||||
}
|
||||
} catch (Throwable cause) {
|
||||
LOGGER.debug(
|
||||
"Unable to use MacOSDnsServerAddressStreamProvider, fallback to system defaults", cause);
|
||||
constructor = null;
|
||||
}
|
||||
return current.nameServerAddressStream(hostname);
|
||||
}
|
||||
|
||||
private DnsServerAddressStreamProvider provider() {
|
||||
// If on windows just use the DefaultDnsServerAddressStreamProvider.INSTANCE as otherwise
|
||||
// we will log some error which may be confusing.
|
||||
return PlatformDependent.isWindows() ? DefaultDnsServerAddressStreamProvider.INSTANCE :
|
||||
UnixResolverDnsServerAddressStreamProvider.parseSilently();
|
||||
}
|
||||
};
|
||||
STREAM_PROVIDER_CONSTRUCTOR = constructor;
|
||||
}
|
||||
|
||||
private DnsServerAddressStreamProviders() {
|
||||
}
|
||||
@ -67,6 +83,53 @@ public final class DnsServerAddressStreamProviders {
|
||||
* configuration.
|
||||
*/
|
||||
public static DnsServerAddressStreamProvider platformDefault() {
|
||||
return DEFAULT_DNS_SERVER_ADDRESS_STREAM_PROVIDER;
|
||||
if (STREAM_PROVIDER_CONSTRUCTOR != null) {
|
||||
try {
|
||||
return STREAM_PROVIDER_CONSTRUCTOR.newInstance();
|
||||
} catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return unixDefault();
|
||||
}
|
||||
|
||||
public static DnsServerAddressStreamProvider unixDefault() {
|
||||
return DefaultProviderHolder.DEFAULT_DNS_SERVER_ADDRESS_STREAM_PROVIDER;
|
||||
}
|
||||
|
||||
// We use a Holder class to only initialize DEFAULT_DNS_SERVER_ADDRESS_STREAM_PROVIDER if we really
|
||||
// need it.
|
||||
private static final class DefaultProviderHolder {
|
||||
// We use 5 minutes which is the same as what OpenJDK is using in sun.net.dns.ResolverConfigurationImpl.
|
||||
private static final long REFRESH_INTERVAL = TimeUnit.MINUTES.toNanos(5);
|
||||
|
||||
// TODO(scott): how is this done on Windows? This may require a JNI call to GetNetworkParams
|
||||
// https://msdn.microsoft.com/en-us/library/aa365968(VS.85).aspx.
|
||||
static final DnsServerAddressStreamProvider DEFAULT_DNS_SERVER_ADDRESS_STREAM_PROVIDER =
|
||||
new DnsServerAddressStreamProvider() {
|
||||
private volatile DnsServerAddressStreamProvider currentProvider = provider();
|
||||
private final AtomicLong lastRefresh = new AtomicLong(System.nanoTime());
|
||||
|
||||
@Override
|
||||
public DnsServerAddressStream nameServerAddressStream(String hostname) {
|
||||
long last = lastRefresh.get();
|
||||
DnsServerAddressStreamProvider current = currentProvider;
|
||||
if (System.nanoTime() - last > REFRESH_INTERVAL) {
|
||||
// This is slightly racy which means it will be possible still use the old configuration
|
||||
// for a small amount of time, but that's ok.
|
||||
if (lastRefresh.compareAndSet(last, System.nanoTime())) {
|
||||
current = currentProvider = provider();
|
||||
}
|
||||
}
|
||||
return current.nameServerAddressStream(hostname);
|
||||
}
|
||||
|
||||
private DnsServerAddressStreamProvider provider() {
|
||||
// If on windows just use the DefaultDnsServerAddressStreamProvider.INSTANCE as otherwise
|
||||
// we will log some error which may be confusing.
|
||||
return PlatformDependent.isWindows() ? DefaultDnsServerAddressStreamProvider.INSTANCE :
|
||||
UnixResolverDnsServerAddressStreamProvider.parseSilently();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2020 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/package io.netty.resolver.dns;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DnsServerAddressStreamProvidersTest {
|
||||
|
||||
@Test
|
||||
public void testUseCorrectProvider() {
|
||||
Assert.assertSame(DnsServerAddressStreamProviders.unixDefault(),
|
||||
DnsServerAddressStreamProviders.platformDefault());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user