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;
16import java.util.stream.Collectors;
17
18import org.minidns.dnsserverlookup.AbstractDnsServerLookupMechanism;
19import org.minidns.dnsserverlookup.AndroidUsingExec;
20
21public class AndroidUsingLinkProperties extends AbstractDnsServerLookupMechanism {
22
23 private final Context context;
24
25 AndroidUsingLinkProperties(Context context) {
26 super(AndroidUsingLinkProperties.class.getSimpleName(), AndroidUsingExec.PRIORITY - 1);
27 this.context = context;
28 }
29
30 @Override
31 public boolean isAvailable() {
32 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
33 }
34
35 @Override
36 @TargetApi(21)
37 public List<String> getDnsServerAddresses() {
38 final ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
39 final Network[] networks = connectivityManager == null ? null : connectivityManager.getAllNetworks();
40 if (networks == null) {
41 return new ArrayList<>();
42 }
43 final Network activeNetwork = getActiveNetwork(connectivityManager);
44 final List<String> networkServers = new ArrayList<>();
45 final List<String> otherServers = new ArrayList<>();
46 for(Network network : networks) {
47 LinkProperties linkProperties = connectivityManager.getLinkProperties(network);
48 if (linkProperties == null) {
49 continue;
50 }
51 final NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
52 final boolean isActiveNetwork = network.equals(activeNetwork);
53 final boolean isVpn = networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_VPN;
54 final List<String> servers = getIPv4First(linkProperties.getDnsServers());
55 if (hasDefaultRoute(linkProperties) || isActiveNetwork || activeNetwork == null || isVpn) {
56 if (isActiveNetwork || isVpn) networkServers.addAll(servers);
57 otherServers.addAll(servers);
58 }
59 }
60 return (networkServers.isEmpty() ? otherServers : networkServers).stream().distinct().collect(Collectors.toList());
61 }
62
63 @TargetApi(23)
64 private static Network getActiveNetwork(ConnectivityManager cm) {
65 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? cm.getActiveNetwork() : null;
66 }
67
68 private static List<String> getIPv4First(List<InetAddress> in) {
69 List<String> out = new ArrayList<>();
70 for(InetAddress address : in) {
71 if (address instanceof Inet4Address) {
72 out.add(0, address.getHostAddress());
73 } else {
74 out.add(address.getHostAddress());
75 }
76 }
77 return out;
78 }
79
80 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
81 private static boolean hasDefaultRoute(LinkProperties linkProperties) {
82 for(RouteInfo route: linkProperties.getRoutes()) {
83 if (route.isDefaultRoute()) {
84 return true;
85 }
86 }
87 return false;
88 }
89}