1 /*
2  * Copyright (C) 2018, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.connectivity;
18 
19 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
20 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
21 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
22 import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
23 import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
24 import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
25 
26 import static org.junit.Assert.assertEquals;
27 import static org.junit.Assert.assertFalse;
28 import static org.junit.Assert.assertNull;
29 import static org.junit.Assert.assertTrue;
30 import static org.mockito.Mockito.when;
31 
32 import android.content.ContentResolver;
33 import android.content.Context;
34 import android.net.IpPrefix;
35 import android.net.LinkAddress;
36 import android.net.LinkProperties;
37 import android.net.Network;
38 import android.net.RouteInfo;
39 import android.os.INetworkManagementService;
40 import android.provider.Settings;
41 import android.support.test.filters.SmallTest;
42 import android.support.test.runner.AndroidJUnit4;
43 import android.test.mock.MockContentResolver;
44 
45 import com.android.internal.util.test.FakeSettingsProvider;
46 import com.android.server.connectivity.DnsManager.PrivateDnsConfig;
47 import com.android.server.connectivity.MockableSystemProperties;
48 
49 import java.net.InetAddress;
50 import java.util.Arrays;
51 
52 import org.junit.runner.RunWith;
53 import org.junit.Before;
54 import org.junit.Test;
55 import org.mockito.Mock;
56 import org.mockito.MockitoAnnotations;
57 
58 /**
59  * Tests for {@link DnsManager}.
60  *
61  * Build, install and run with:
62  *  runtest frameworks-net -c com.android.server.connectivity.DnsManagerTest
63  */
64 @RunWith(AndroidJUnit4.class)
65 @SmallTest
66 public class DnsManagerTest {
67     static final String TEST_IFACENAME = "test_wlan0";
68     static final int TEST_NETID = 100;
69     static final int TEST_NETID_ALTERNATE = 101;
70     static final int TEST_NETID_UNTRACKED = 102;
71     final boolean IS_DEFAULT = true;
72     final boolean NOT_DEFAULT = false;
73 
74     DnsManager mDnsManager;
75     MockContentResolver mContentResolver;
76 
77     @Mock Context mCtx;
78     @Mock INetworkManagementService mNMService;
79     @Mock MockableSystemProperties mSystemProperties;
80 
81     @Before
setUp()82     public void setUp() throws Exception {
83         MockitoAnnotations.initMocks(this);
84         mContentResolver = new MockContentResolver();
85         mContentResolver.addProvider(Settings.AUTHORITY,
86                 new FakeSettingsProvider());
87         when(mCtx.getContentResolver()).thenReturn(mContentResolver);
88         mDnsManager = new DnsManager(mCtx, mNMService, mSystemProperties);
89 
90         // Clear the private DNS settings
91         Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "");
92         Settings.Global.putString(mContentResolver, PRIVATE_DNS_MODE, "");
93         Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "");
94     }
95 
96     @Test
testTrackedValidationUpdates()97     public void testTrackedValidationUpdates() throws Exception {
98         mDnsManager.updatePrivateDns(new Network(TEST_NETID),
99                 mDnsManager.getPrivateDnsConfig());
100         mDnsManager.updatePrivateDns(new Network(TEST_NETID_ALTERNATE),
101                 mDnsManager.getPrivateDnsConfig());
102         LinkProperties lp = new LinkProperties();
103         lp.setInterfaceName(TEST_IFACENAME);
104         lp.addDnsServer(InetAddress.getByName("3.3.3.3"));
105         lp.addDnsServer(InetAddress.getByName("4.4.4.4"));
106 
107         // Send a validation event that is tracked on the alternate netId
108         mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT);
109         mDnsManager.setDnsConfigurationForNetwork(TEST_NETID_ALTERNATE, lp, NOT_DEFAULT);
110         mDnsManager.updatePrivateDnsValidation(
111                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_ALTERNATE,
112                 InetAddress.parseNumericAddress("4.4.4.4"), "", true));
113         LinkProperties fixedLp = new LinkProperties(lp);
114         mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
115         assertFalse(fixedLp.isPrivateDnsActive());
116         assertNull(fixedLp.getPrivateDnsServerName());
117         fixedLp = new LinkProperties(lp);
118         mDnsManager.updatePrivateDnsStatus(TEST_NETID_ALTERNATE, fixedLp);
119         assertTrue(fixedLp.isPrivateDnsActive());
120         assertNull(fixedLp.getPrivateDnsServerName());
121         assertEquals(Arrays.asList(InetAddress.getByName("4.4.4.4")),
122                 fixedLp.getValidatedPrivateDnsServers());
123 
124         // Set up addresses for strict mode and switch to it.
125         lp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
126         lp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"),
127                 TEST_IFACENAME));
128         lp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
129         lp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"),
130                 TEST_IFACENAME));
131 
132         Settings.Global.putString(mContentResolver,
133                 PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
134         Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com");
135         mDnsManager.updatePrivateDns(new Network(TEST_NETID),
136                 new DnsManager.PrivateDnsConfig("strictmode.com", new InetAddress[] {
137                     InetAddress.parseNumericAddress("6.6.6.6"),
138                     InetAddress.parseNumericAddress("2001:db8:66:66::1")
139                     }));
140         mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT);
141         fixedLp = new LinkProperties(lp);
142         mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
143         assertTrue(fixedLp.isPrivateDnsActive());
144         assertEquals("strictmode.com", fixedLp.getPrivateDnsServerName());
145         // No validation events yet.
146         assertEquals(Arrays.asList(new InetAddress[0]), fixedLp.getValidatedPrivateDnsServers());
147         // Validate one.
148         mDnsManager.updatePrivateDnsValidation(
149                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
150                 InetAddress.parseNumericAddress("6.6.6.6"), "strictmode.com", true));
151         fixedLp = new LinkProperties(lp);
152         mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
153         assertEquals(Arrays.asList(InetAddress.parseNumericAddress("6.6.6.6")),
154                 fixedLp.getValidatedPrivateDnsServers());
155         // Validate the 2nd one.
156         mDnsManager.updatePrivateDnsValidation(
157                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
158                 InetAddress.parseNumericAddress("2001:db8:66:66::1"), "strictmode.com", true));
159         fixedLp = new LinkProperties(lp);
160         mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
161         assertEquals(Arrays.asList(
162                         InetAddress.parseNumericAddress("2001:db8:66:66::1"),
163                         InetAddress.parseNumericAddress("6.6.6.6")),
164                 fixedLp.getValidatedPrivateDnsServers());
165     }
166 
167     @Test
testIgnoreUntrackedValidationUpdates()168     public void testIgnoreUntrackedValidationUpdates() throws Exception {
169         // The PrivateDnsConfig map is empty, so no validation events will
170         // be tracked.
171         LinkProperties lp = new LinkProperties();
172         lp.addDnsServer(InetAddress.getByName("3.3.3.3"));
173         mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT);
174         mDnsManager.updatePrivateDnsValidation(
175                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
176                 InetAddress.parseNumericAddress("3.3.3.3"), "", true));
177         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
178         assertFalse(lp.isPrivateDnsActive());
179         assertNull(lp.getPrivateDnsServerName());
180 
181         // Validation event has untracked netId
182         mDnsManager.updatePrivateDns(new Network(TEST_NETID),
183                 mDnsManager.getPrivateDnsConfig());
184         mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT);
185         mDnsManager.updatePrivateDnsValidation(
186                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_UNTRACKED,
187                 InetAddress.parseNumericAddress("3.3.3.3"), "", true));
188         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
189         assertFalse(lp.isPrivateDnsActive());
190         assertNull(lp.getPrivateDnsServerName());
191 
192         // Validation event has untracked ipAddress
193         mDnsManager.updatePrivateDnsValidation(
194                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
195                 InetAddress.parseNumericAddress("4.4.4.4"), "", true));
196         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
197         assertFalse(lp.isPrivateDnsActive());
198         assertNull(lp.getPrivateDnsServerName());
199 
200         // Validation event has untracked hostname
201         mDnsManager.updatePrivateDnsValidation(
202                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
203                 InetAddress.parseNumericAddress("3.3.3.3"), "hostname",
204                 true));
205         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
206         assertFalse(lp.isPrivateDnsActive());
207         assertNull(lp.getPrivateDnsServerName());
208 
209         // Validation event failed
210         mDnsManager.updatePrivateDnsValidation(
211                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
212                 InetAddress.parseNumericAddress("3.3.3.3"), "", false));
213         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
214         assertFalse(lp.isPrivateDnsActive());
215         assertNull(lp.getPrivateDnsServerName());
216 
217         // Network removed
218         mDnsManager.removeNetwork(new Network(TEST_NETID));
219         mDnsManager.updatePrivateDnsValidation(
220                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
221                 InetAddress.parseNumericAddress("3.3.3.3"), "", true));
222         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
223         assertFalse(lp.isPrivateDnsActive());
224         assertNull(lp.getPrivateDnsServerName());
225 
226         // Turn private DNS mode off
227         Settings.Global.putString(mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OFF);
228         mDnsManager.updatePrivateDns(new Network(TEST_NETID),
229                 mDnsManager.getPrivateDnsConfig());
230         mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT);
231         mDnsManager.updatePrivateDnsValidation(
232                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
233                 InetAddress.parseNumericAddress("3.3.3.3"), "", true));
234         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
235         assertFalse(lp.isPrivateDnsActive());
236         assertNull(lp.getPrivateDnsServerName());
237     }
238 
239     @Test
testOverrideDefaultMode()240     public void testOverrideDefaultMode() throws Exception {
241         // Hard-coded default is opportunistic mode.
242         final PrivateDnsConfig cfgAuto = DnsManager.getPrivateDnsConfig(mContentResolver);
243         assertTrue(cfgAuto.useTls);
244         assertEquals("", cfgAuto.hostname);
245         assertEquals(new InetAddress[0], cfgAuto.ips);
246 
247         // Pretend a gservices push sets the default to "off".
248         Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "off");
249         final PrivateDnsConfig cfgOff = DnsManager.getPrivateDnsConfig(mContentResolver);
250         assertFalse(cfgOff.useTls);
251         assertEquals("", cfgOff.hostname);
252         assertEquals(new InetAddress[0], cfgOff.ips);
253 
254         // Strict mode still works.
255         Settings.Global.putString(
256                 mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
257         Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com");
258         final PrivateDnsConfig cfgStrict = DnsManager.getPrivateDnsConfig(mContentResolver);
259         assertTrue(cfgStrict.useTls);
260         assertEquals("strictmode.com", cfgStrict.hostname);
261         assertEquals(new InetAddress[0], cfgStrict.ips);
262     }
263 }
264