001/* 002 * Copyright 2015-2020 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.android21; 012 013import android.annotation.TargetApi; 014import android.content.Context; 015import android.net.ConnectivityManager; 016import android.net.LinkProperties; 017import android.net.Network; 018import android.net.RouteInfo; 019import android.os.Build; 020 021import java.util.ArrayList; 022import java.util.List; 023 024import org.minidns.DnsClient; 025import org.minidns.dnsserverlookup.AbstractDnsServerLookupMechanism; 026import org.minidns.dnsserverlookup.AndroidUsingExec; 027 028/** 029 * A DNS server lookup mechanism using Android's Link Properties method available on Android API 21 or higher. Use 030 * {@link #setup(Context)} to setup this mechanism. 031 * <p> 032 * Requires the ACCESS_NETWORK_STATE permission. 033 * </p> 034 */ 035public class AndroidUsingLinkProperties extends AbstractDnsServerLookupMechanism { 036 037 private final ConnectivityManager connectivityManager; 038 039 /** 040 * Setup this DNS server lookup mechanism. You need to invoke this method only once, ideally before you do your 041 * first DNS lookup. 042 * 043 * @param context a Context instance. 044 * @return the instance of the newly setup mechanism 045 */ 046 public static AndroidUsingLinkProperties setup(Context context) { 047 AndroidUsingLinkProperties androidUsingLinkProperties = new AndroidUsingLinkProperties(context); 048 DnsClient.addDnsServerLookupMechanism(androidUsingLinkProperties); 049 return androidUsingLinkProperties; 050 } 051 052 public AndroidUsingLinkProperties(Context context) { 053 super(AndroidUsingLinkProperties.class.getSimpleName(), AndroidUsingExec.PRIORITY - 1); 054 connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 055 } 056 057 @Override 058 public boolean isAvailable() { 059 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; 060 } 061 062 @Override 063 @TargetApi(21) 064 public List<String> getDnsServerAddresses() { 065 Network[] networks = connectivityManager.getAllNetworks(); 066 if (networks == null) { 067 return null; 068 } 069 070 List<String> servers = new ArrayList<>(networks.length * 2); 071 for (Network network : networks) { 072 LinkProperties linkProperties = connectivityManager.getLinkProperties(network); 073 if (linkProperties == null) { 074 continue; 075 } 076 077 // Prioritize the DNS servers of links which have a default route 078 if (hasDefaultRoute(linkProperties)) { 079 servers.addAll(0, toListOfStrings(linkProperties.getDnsServers())); 080 } else { 081 servers.addAll(toListOfStrings(linkProperties.getDnsServers())); 082 } 083 } 084 085 if (servers.isEmpty()) { 086 return null; 087 } 088 089 return servers; 090 } 091 092 @TargetApi(Build.VERSION_CODES.LOLLIPOP) 093 private static boolean hasDefaultRoute(LinkProperties linkProperties) { 094 for (RouteInfo route : linkProperties.getRoutes()) { 095 if (route.isDefaultRoute()) { 096 return true; 097 } 098 } 099 return false; 100 } 101 102}