android dhcp dns1 dns2,How do you get the current DNS servers for Android?

Unfortunatelly most solutions presented are NOT working anymore in Android 8.0

Official Android documentation state this very clearly in the article Android 8.0 Behavior Changes.

The system properties net.dns1, net.dns2, net.dns3, and net.dns4 are no longer available, a change that improves privacy on the platform.

Dnsjava library is also afected and the detection methods used in dnsjava are not aware of Oreo changes.

Varun Anand solution works on Oreo but have an weakness in not handling connection with default routes. Because of this the result maybe poisoned with invalid DNS servers comming first into the result and the caller may spend a lot of time iterating the list and trying to connect to unreacheble DNS servers. This was fixed into my solution. Another problem with Varun Anand solution is this only works for API 21 and above. But i must say it was gold mine for me to write my own solution. So thank's!

For your convenience i provided a full DNS servers detector class you can use that works on any android version.

Full comments are included to answer to why and how.

/**

* DNS servers detector

*

* IMPORTANT: don't cache the result.

*

* Or if you want to cache the result make sure you invalidate the cache

* on any network change.

*

* It is always better to use a new instance of the detector when you need

* current DNS servers otherwise you may get into troubles because of invalid/changed

* DNS servers.

*

* This class combines various methods and solutions from:

* Dnsjava http://www.xbill.org/dnsjava/

* Minidns https://github.com/MiniDNS/minidns

*

* Unfortunately both libraries are not aware of Orero changes so new method was added to fix this.

*

* Created by Madalin Grigore-Enescu on 2/24/18.

*/

public class DnsServersDetector {

private static final String TAG = "DnsServersDetector";

/**

* Holds some default DNS servers used in case all DNS servers detection methods fail.

* Can be set to null if you want caller to fail in this situation.

*/

private static final String[] FACTORY_DNS_SERVERS = {

"8.8.8.8",

"8.8.4.4"

};

/**

* Properties delimiter used in exec method of DNS servers detection

*/

private static final String METHOD_EXEC_PROP_DELIM = "]: [";

/**

* Holds context this was created under

*/

private Context context;

//region - public //

/**

* Constructor

*/

public DnsServersDetector(Context context) {

this.context = context;

}

/**

* Returns android DNS servers used for current connected network

* @return Dns servers array

*/

public String [] getServers() {

// Will hold the consecutive result

String[] result;

// METHOD 1: old deprecated system properties

result = getServersMethodSystemProperties();

if (result != null && result.length > 0) {

return result;

}

// METHOD 2 - use connectivity manager

result = getServersMethodConnectivityManager();

if (result != null && result.length > 0) {

return result;

}

// LAST METHOD: detect android DNS servers by executing getprop string command in a separate process

// This method fortunately works in Oreo too but many people may want to avoid exec

// so it's used only as a failsafe scenario

result = getServersMethodExec();

if (result != null && result.length > 0) {

return result;

}

// Fall back on factory DNS servers

return FACTORY_DNS_SERVERS;

}

//endregion

//region - private /

/**

* Detect android DNS servers by using connectivity manager

*

* This method is working in android LOLLIPOP or later

*

* @return Dns servers array

*/

private String [] getServersMethodConnectivityManager() {

// This code only works on LOLLIPOP and higher

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

try {

ArrayList priorityServersArrayList = new ArrayList<>();

ArrayList serversArrayList = new ArrayList<>();

ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(CONNECTIVITY_SERVICE);

if (connectivityManager != null) {

// Iterate all networks

// Notice that android LOLLIPOP or higher allow iterating multiple connected networks of SAME type

for (Network network : connectivityManager.getAllNetworks()) {

NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);

if (networkInfo.isConnected()) {

LinkProperties linkProperties = connectivityManager.getLinkProperties(network);

List dnsServersList = linkProperties.getDnsServers();

// Prioritize the DNS servers for link which have a default route

if (linkPropertiesHasDefaultRoute(linkProperties)) {

for (InetAddress element: dnsServersList) {

String dnsHost = element.getHostAddress();

priorityServersArrayList.add(dnsHost);

}

} else {

for (InetAddress element: dnsServersList) {

String dnsHost = element.getHostAddress();

serversArrayList.add(dnsHost);

}

}

}

}

}

// Append secondary arrays only if priority is empty

if (priorityServersArrayList.isEmpty()) {

priorityServersArrayList.addAll(serversArrayList);

}

// Stop here if we have at least one DNS server

if (priorityServersArrayList.size() > 0) {

return priorityServersArrayList.toArray(new String[0]);

}

} catch (Exception ex) {

Log.d(TAG, "Exception detecting DNS servers using ConnectivityManager method", ex);

}

}

// Failure

return null;

}

/**

* Detect android DNS servers by using old deprecated system properties

*

* This method is NOT working anymore in Android 8.0

* Official Android documentation state this in the article Android 8.0 Behavior Changes.

* The system properties net.dns1, net.dns2, net.dns3, and net.dns4 are no longer available,

* a change that improves privacy on the platform.

*

* https://developer.android.com/about/versions/oreo/android-8.0-changes.html#o-pri

* @return Dns servers array

*/

private String [] getServersMethodSystemProperties() {

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {

// This originally looked for all lines containing .dns; but

// http://code.google.com/p/android/issues/detail?id=2207#c73

// indicates that net.dns* should always be the active nameservers, so

// we use those.

final String re1 = "^\\d+(\\.\\d+){3}$";

final String re2 = "^[0-9a-f]+(:[0-9a-f]*)+:[0-9a-f]+$";

ArrayList serversArrayList = new ArrayList<>();

try {

Class SystemProperties = Class.forName("android.os.SystemProperties");

Method method = SystemProperties.getMethod("get", new Class[]{String.class});

final String[] netdns = new String[]{"net.dns1", "net.dns2", "net.dns3", "net.dns4"};

for (int i = 0; i < netdns.length; i++) {

Object[] args = new Object[]{netdns[i]};

String v = (String) method.invoke(null, args);

if (v != null && (v.matches(re1) || v.matches(re2)) && !serversArrayList.contains(v)) {

serversArrayList.add(v);

}

}

// Stop here if we have at least one DNS server

if (serversArrayList.size() > 0) {

return serversArrayList.toArray(new String[0]);

}

} catch (Exception ex) {

Log.d(TAG, "Exception detecting DNS servers using SystemProperties method", ex);

}

}

// Failed

return null;

}

/**

* Detect android DNS servers by executing getprop string command in a separate process

*

* Notice there is an android bug when Runtime.exec() hangs without providing a Process object.

* This problem is fixed in Jelly Bean (Android 4.1) but not in ICS (4.0.4) and probably it will never be fixed in ICS.

* https://stackoverflow.com/questions/8688382/runtime-exec-bug-hangs-without-providing-a-process-object/11362081

*

* @return Dns servers array

*/

private String [] getServersMethodExec() {

// We are on the safe side and avoid any bug

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {

try {

Process process = Runtime.getRuntime().exec("getprop");

InputStream inputStream = process.getInputStream();

LineNumberReader lineNumberReader = new LineNumberReader(new InputStreamReader(inputStream));

Set serversSet = methodExecParseProps(lineNumberReader);

if (serversSet != null && serversSet.size() > 0) {

return serversSet.toArray(new String[0]);

}

} catch (Exception ex) {

Log.d(TAG, "Exception in getServersMethodExec", ex);

}

}

// Failed

return null;

}

/**

* Parse properties produced by executing getprop command

* @param lineNumberReader

* @return Set of parsed properties

* @throws Exception

*/

private Set methodExecParseProps(BufferedReader lineNumberReader) throws Exception {

String line;

Set serversSet = new HashSet(10);

while ((line = lineNumberReader.readLine()) != null) {

int split = line.indexOf(METHOD_EXEC_PROP_DELIM);

if (split == -1) {

continue;

}

String property = line.substring(1, split);

int valueStart = split + METHOD_EXEC_PROP_DELIM.length();

int valueEnd = line.length() - 1;

if (valueEnd < valueStart) {

// This can happen if a newline sneaks in as the first character of the property value. For example

// "[propName]: [\n…]".

Log.d(TAG, "Malformed property detected: \"" + line + '"');

continue;

}

String value = line.substring(valueStart, valueEnd);

if (value.isEmpty()) {

continue;

}

if (property.endsWith(".dns") || property.endsWith(".dns1") ||

property.endsWith(".dns2") || property.endsWith(".dns3") ||

property.endsWith(".dns4")) {

// normalize the address

InetAddress ip = InetAddress.getByName(value);

if (ip == null) continue;

value = ip.getHostAddress();

if (value == null) continue;

if (value.length() == 0) continue;

serversSet.add(value);

}

}

return serversSet;

}

/**

* Returns true if the specified link properties have any default route

* @param linkProperties

* @return true if the specified link properties have default route or false otherwise

*/

@TargetApi(Build.VERSION_CODES.LOLLIPOP)

private boolean linkPropertiesHasDefaultRoute(LinkProperties linkProperties) {

for (RouteInfo route : linkProperties.getRoutes()) {

if (route.isDefaultRoute()) {

return true;

}

}

return false;

}

//endregion

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值