1package eu.siacs.conversations.utils;
2
3import android.annotation.TargetApi;
4import android.content.Context;
5import android.net.ConnectivityManager;
6import android.net.LinkProperties;
7import android.net.Network;
8import android.net.NetworkInfo;
9import android.net.RouteInfo;
10import android.os.Build;
11
12import java.net.Inet4Address;
13import java.net.InetAddress;
14import java.util.ArrayList;
15import java.util.List;
16
17import de.measite.minidns.dnsserverlookup.AbstractDNSServerLookupMechanism;
18import de.measite.minidns.dnsserverlookup.AndroidUsingExec;
19
20public class AndroidUsingLinkProperties extends AbstractDNSServerLookupMechanism {
21
22 private final Context context;
23
24 protected AndroidUsingLinkProperties(Context context) {
25 super(AndroidUsingLinkProperties.class.getSimpleName(), AndroidUsingExec.PRIORITY - 1);
26 this.context = context;
27 }
28
29 @Override
30 public boolean isAvailable() {
31 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
32 }
33
34 @Override
35 @TargetApi(21)
36 public String[] getDnsServerAddresses() {
37 ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
38 Network[] networks = connectivityManager == null ? null : connectivityManager.getAllNetworks();
39 if (networks == null) {
40 return new String[0];
41 }
42 final Network activeNetwork = getActiveNetwork(connectivityManager);
43 List<String> servers = new ArrayList<>();
44 int vpnOffset = 0;
45 for(Network network : networks) {
46 LinkProperties linkProperties = connectivityManager.getLinkProperties(network);
47 NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
48 final boolean isActiveNetwork = network.equals(activeNetwork);
49 if (linkProperties != null) {
50 if (networkInfo != null && isActiveNetwork && networkInfo.getType() == ConnectivityManager.TYPE_VPN) {
51 final List<String> tmp = getIPv4First(linkProperties.getDnsServers());
52 servers.addAll(0, tmp);
53 vpnOffset += tmp.size();
54 } else if (hasDefaultRoute(linkProperties)) {
55 servers.addAll(vpnOffset, getIPv4First(linkProperties.getDnsServers()));
56 } else {
57 servers.addAll(getIPv4First(linkProperties.getDnsServers()));
58 }
59 }
60 }
61 return servers.toArray(new String[servers.size()]);
62 }
63
64 @TargetApi(23)
65 private static Network getActiveNetwork(ConnectivityManager cm) {
66 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? cm.getActiveNetwork() : null;
67 }
68
69 private static List<String> getIPv4First(List<InetAddress> in) {
70 List<String> out = new ArrayList<>();
71 for(InetAddress addr : in) {
72 if (addr instanceof Inet4Address) {
73 out.add(0, addr.getHostAddress());
74 } else {
75 out.add(addr.getHostAddress());
76 }
77 }
78 return out;
79 }
80
81 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
82 private static boolean hasDefaultRoute(LinkProperties linkProperties) {
83 for(RouteInfo route: linkProperties.getRoutes()) {
84 if (route.isDefaultRoute()) {
85 return true;
86 }
87 }
88 return false;
89 }
90}