AndroidDNSClient.java

  1package de.gultsch.minidns;
  2
  3import android.content.Context;
  4import android.net.ConnectivityManager;
  5import android.net.LinkProperties;
  6import android.net.Network;
  7import android.os.Build;
  8
  9import com.google.common.base.Strings;
 10import com.google.common.collect.ImmutableList;
 11
 12import de.measite.minidns.AbstractDNSClient;
 13import de.measite.minidns.DNSMessage;
 14
 15import java.io.IOException;
 16import java.net.InetAddress;
 17import java.util.List;
 18
 19public class AndroidDNSClient extends AbstractDNSClient {
 20    private final Context context;
 21    private final NetworkDataSource networkDataSource = new NetworkDataSource();
 22    private boolean askForDnssec = false;
 23
 24    public AndroidDNSClient(final Context context) {
 25        super();
 26        this.setDataSource(networkDataSource);
 27        this.context = context;
 28    }
 29
 30    private static String getPrivateDnsServerName(final LinkProperties linkProperties) {
 31        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
 32            return linkProperties.getPrivateDnsServerName();
 33        } else {
 34            return null;
 35        }
 36    }
 37
 38    private static boolean isPrivateDnsActive(final LinkProperties linkProperties) {
 39        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
 40            return linkProperties.isPrivateDnsActive();
 41        } else {
 42            return false;
 43        }
 44    }
 45
 46    @Override
 47    protected DNSMessage.Builder newQuestion(final DNSMessage.Builder message) {
 48        message.setRecursionDesired(true);
 49        message.getEdnsBuilder()
 50                .setUdpPayloadSize(networkDataSource.getUdpPayloadSize())
 51                .setDnssecOk(askForDnssec);
 52        return message;
 53    }
 54
 55    @Override
 56    protected DNSMessage query(final DNSMessage.Builder queryBuilder) throws IOException {
 57        final DNSMessage question = newQuestion(queryBuilder).build();
 58        for (final DNSServer dnsServer : getDNSServers()) {
 59            final DNSMessage response = this.networkDataSource.query(question, dnsServer);
 60            if (response == null) {
 61                continue;
 62            }
 63            switch (response.responseCode) {
 64                case NO_ERROR:
 65                case NX_DOMAIN:
 66                    break;
 67                default:
 68                    continue;
 69            }
 70
 71            return response;
 72        }
 73        return null;
 74    }
 75
 76    public boolean isAskForDnssec() {
 77        return askForDnssec;
 78    }
 79
 80    public void setAskForDnssec(boolean askForDnssec) {
 81        this.askForDnssec = askForDnssec;
 82    }
 83
 84    private List<DNSServer> getDNSServers() {
 85        final ImmutableList.Builder<DNSServer> dnsServerBuilder = new ImmutableList.Builder<>();
 86        final ConnectivityManager connectivityManager =
 87                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
 88        final Network[] networks = getActiveNetworks(connectivityManager);
 89        for (final Network network : networks) {
 90            final LinkProperties linkProperties = connectivityManager.getLinkProperties(network);
 91            if (linkProperties == null) {
 92                continue;
 93            }
 94            final String privateDnsServerName = getPrivateDnsServerName(linkProperties);
 95            if (Strings.isNullOrEmpty(privateDnsServerName)) {
 96                final boolean isPrivateDns = isPrivateDnsActive(linkProperties);
 97                for (final InetAddress dnsServer : linkProperties.getDnsServers()) {
 98                    if (isPrivateDns) {
 99                        dnsServerBuilder.add(new DNSServer(dnsServer, Transport.TLS));
100                    } else {
101                        dnsServerBuilder.add(new DNSServer(dnsServer));
102                    }
103                }
104            } else {
105                dnsServerBuilder.add(new DNSServer(privateDnsServerName, Transport.TLS));
106            }
107        }
108        return dnsServerBuilder.build();
109    }
110
111    private Network[] getActiveNetworks(final ConnectivityManager connectivityManager) {
112        if (connectivityManager == null) {
113            return new Network[0];
114        }
115        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
116            final Network activeNetwork = connectivityManager.getActiveNetwork();
117            if (activeNetwork != null) {
118                return new Network[] {activeNetwork};
119            }
120        }
121        return connectivityManager.getAllNetworks();
122    }
123}