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.dnsserverlookup;
012
013import org.minidns.util.PlatformDetection;
014
015import java.lang.reflect.InvocationTargetException;
016import java.lang.reflect.Method;
017import java.net.InetAddress;
018import java.net.UnknownHostException;
019import java.util.ArrayList;
020import java.util.List;
021import java.util.logging.Level;
022
023/**
024 * Try to retrieve the list of DNS server by calling SystemProperties.
025 */
026public class AndroidUsingReflection extends AbstractDnsServerLookupMechanism {
027
028    public static final DnsServerLookupMechanism INSTANCE = new AndroidUsingReflection();
029    public static final int PRIORITY = 1000;
030
031    private final Method systemPropertiesGet;
032
033    protected AndroidUsingReflection() {
034        super(AndroidUsingReflection.class.getSimpleName(), PRIORITY);
035        Method systemPropertiesGet = null;
036        if (PlatformDetection.isAndroid()) {
037            try {
038                Class<?> SystemProperties = Class.forName("android.os.SystemProperties");
039                systemPropertiesGet = SystemProperties.getMethod("get", new Class<?>[] { String.class });
040            } catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
041                // This is not unexpected, as newer Android versions do not provide access to it any more.
042                LOGGER.log(Level.FINE, "Can not get method handle for android.os.SystemProperties.get(String).", e);
043            }
044        }
045        this.systemPropertiesGet = systemPropertiesGet;
046    }
047
048    @Override
049    public List<String> getDnsServerAddresses() {
050        ArrayList<String> servers = new ArrayList<String>(5);
051
052        for (String propKey : new String[] {
053                "net.dns1", "net.dns2", "net.dns3", "net.dns4"}) {
054
055            String value;
056            try {
057                value = (String) systemPropertiesGet.invoke(null, propKey);
058            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
059                LOGGER.log(Level.WARNING, "Exception in findDNSByReflection", e);
060                return null;
061            }
062
063            if (value == null) continue;
064            if (value.length() == 0) continue;
065            if (servers.contains(value)) continue;
066
067            InetAddress ip;
068            try {
069                ip = InetAddress.getByName(value);
070            } catch (UnknownHostException e) {
071                LOGGER.log(Level.WARNING, "Exception in findDNSByReflection", e);
072                continue;
073            }
074
075            if (ip == null) continue;
076
077            value = ip.getHostAddress();
078
079            if (value == null) continue;
080            if (value.length() == 0) continue;
081            if (servers.contains(value)) continue;
082
083            servers.add(value);
084        }
085
086        if (servers.size() > 0) {
087            return servers;
088        }
089
090        return null;
091    }
092
093    @Override
094    public boolean isAvailable() {
095        return systemPropertiesGet != null;
096    }
097
098}