1 /* 2 * Copyright (C) 2017 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 org.junit.Assert.assertFalse; 20 import static org.junit.Assert.assertNull; 21 import static org.junit.Assert.assertTrue; 22 import static org.mockito.Mockito.any; 23 import static org.mockito.Mockito.eq; 24 import static org.mockito.Mockito.times; 25 import static org.mockito.Mockito.verify; 26 import static org.mockito.Mockito.verifyNoMoreInteractions; 27 import static org.mockito.Mockito.when; 28 29 import android.net.ConnectivityManager; 30 import android.net.InterfaceConfiguration; 31 import android.net.LinkAddress; 32 import android.net.LinkProperties; 33 import android.net.NetworkInfo; 34 import android.os.Handler; 35 import android.os.INetworkManagementService; 36 import android.os.test.TestLooper; 37 import android.support.test.filters.SmallTest; 38 import android.support.test.runner.AndroidJUnit4; 39 40 import com.android.server.ConnectivityService; 41 42 import org.junit.Before; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 import org.mockito.ArgumentCaptor; 46 import org.mockito.Mock; 47 import org.mockito.MockitoAnnotations; 48 49 @RunWith(AndroidJUnit4.class) 50 @SmallTest 51 public class Nat464XlatTest { 52 53 static final String BASE_IFACE = "test0"; 54 static final String STACKED_IFACE = "v4-test0"; 55 static final LinkAddress ADDR = new LinkAddress("192.0.2.5/29"); 56 57 @Mock ConnectivityService mConnectivity; 58 @Mock INetworkManagementService mNms; 59 @Mock InterfaceConfiguration mConfig; 60 @Mock NetworkAgentInfo mNai; 61 62 TestLooper mLooper; 63 Handler mHandler; 64 makeNat464Xlat()65 Nat464Xlat makeNat464Xlat() { 66 return new Nat464Xlat(mNms, mNai); 67 } 68 69 @Before setUp()70 public void setUp() throws Exception { 71 mLooper = new TestLooper(); 72 mHandler = new Handler(mLooper.getLooper()); 73 74 MockitoAnnotations.initMocks(this); 75 76 mNai.linkProperties = new LinkProperties(); 77 mNai.linkProperties.setInterfaceName(BASE_IFACE); 78 mNai.networkInfo = new NetworkInfo(null); 79 mNai.networkInfo.setType(ConnectivityManager.TYPE_WIFI); 80 when(mNai.connService()).thenReturn(mConnectivity); 81 when(mNai.handler()).thenReturn(mHandler); 82 83 when(mNms.getInterfaceConfig(eq(STACKED_IFACE))).thenReturn(mConfig); 84 when(mConfig.getLinkAddress()).thenReturn(ADDR); 85 } 86 87 @Test testRequiresClat()88 public void testRequiresClat() throws Exception { 89 final int[] supportedTypes = { 90 ConnectivityManager.TYPE_MOBILE, 91 ConnectivityManager.TYPE_WIFI, 92 ConnectivityManager.TYPE_ETHERNET, 93 }; 94 95 // NetworkInfo doesn't allow setting the State directly, but rather 96 // requires setting DetailedState in order set State as a side-effect. 97 final NetworkInfo.DetailedState[] supportedDetailedStates = { 98 NetworkInfo.DetailedState.CONNECTED, 99 NetworkInfo.DetailedState.SUSPENDED, 100 }; 101 102 for (int type : supportedTypes) { 103 mNai.networkInfo.setType(type); 104 for (NetworkInfo.DetailedState state : supportedDetailedStates) { 105 mNai.networkInfo.setDetailedState(state, "reason", "extraInfo"); 106 assertTrue( 107 String.format("requiresClat expected for type=%d state=%s", type, state), 108 Nat464Xlat.requiresClat(mNai)); 109 } 110 } 111 } 112 113 @Test testNormalStartAndStop()114 public void testNormalStartAndStop() throws Exception { 115 Nat464Xlat nat = makeNat464Xlat(); 116 ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class); 117 118 // ConnectivityService starts clat. 119 nat.start(); 120 121 verify(mNms).registerObserver(eq(nat)); 122 verify(mNms).startClatd(eq(BASE_IFACE)); 123 124 // Stacked interface up notification arrives. 125 nat.interfaceLinkStateChanged(STACKED_IFACE, true); 126 mLooper.dispatchNext(); 127 128 verify(mNms).getInterfaceConfig(eq(STACKED_IFACE)); 129 verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture()); 130 assertFalse(c.getValue().getStackedLinks().isEmpty()); 131 assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE)); 132 assertRunning(nat); 133 134 // ConnectivityService stops clat (Network disconnects, IPv4 addr appears, ...). 135 nat.stop(); 136 137 verify(mNms).stopClatd(eq(BASE_IFACE)); 138 139 // Stacked interface removed notification arrives. 140 nat.interfaceRemoved(STACKED_IFACE); 141 mLooper.dispatchNext(); 142 143 verify(mNms).unregisterObserver(eq(nat)); 144 verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture()); 145 assertTrue(c.getValue().getStackedLinks().isEmpty()); 146 assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE)); 147 assertIdle(nat); 148 149 verifyNoMoreInteractions(mNms, mConnectivity); 150 } 151 152 @Test testClatdCrashWhileRunning()153 public void testClatdCrashWhileRunning() throws Exception { 154 Nat464Xlat nat = makeNat464Xlat(); 155 ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class); 156 157 // ConnectivityService starts clat. 158 nat.start(); 159 160 verify(mNms).registerObserver(eq(nat)); 161 verify(mNms).startClatd(eq(BASE_IFACE)); 162 163 // Stacked interface up notification arrives. 164 nat.interfaceLinkStateChanged(STACKED_IFACE, true); 165 mLooper.dispatchNext(); 166 167 verify(mNms).getInterfaceConfig(eq(STACKED_IFACE)); 168 verify(mConnectivity, times(1)).handleUpdateLinkProperties(eq(mNai), c.capture()); 169 assertFalse(c.getValue().getStackedLinks().isEmpty()); 170 assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE)); 171 assertRunning(nat); 172 173 // Stacked interface removed notification arrives (clatd crashed, ...). 174 nat.interfaceRemoved(STACKED_IFACE); 175 mLooper.dispatchNext(); 176 177 verify(mNms).unregisterObserver(eq(nat)); 178 verify(mNms).stopClatd(eq(BASE_IFACE)); 179 verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture()); 180 assertTrue(c.getValue().getStackedLinks().isEmpty()); 181 assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE)); 182 assertIdle(nat); 183 184 // ConnectivityService stops clat: no-op. 185 nat.stop(); 186 187 verifyNoMoreInteractions(mNms, mConnectivity); 188 } 189 190 @Test testStopBeforeClatdStarts()191 public void testStopBeforeClatdStarts() throws Exception { 192 Nat464Xlat nat = makeNat464Xlat(); 193 194 // ConnectivityService starts clat. 195 nat.start(); 196 197 verify(mNms).registerObserver(eq(nat)); 198 verify(mNms).startClatd(eq(BASE_IFACE)); 199 200 // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...) 201 nat.stop(); 202 203 verify(mNms).unregisterObserver(eq(nat)); 204 verify(mNms).stopClatd(eq(BASE_IFACE)); 205 assertIdle(nat); 206 207 // In-flight interface up notification arrives: no-op 208 nat.interfaceLinkStateChanged(STACKED_IFACE, true); 209 mLooper.dispatchNext(); 210 211 212 // Interface removed notification arrives after stopClatd() takes effect: no-op. 213 nat.interfaceRemoved(STACKED_IFACE); 214 mLooper.dispatchNext(); 215 216 assertIdle(nat); 217 218 verifyNoMoreInteractions(mNms, mConnectivity); 219 } 220 221 @Test testStopAndClatdNeverStarts()222 public void testStopAndClatdNeverStarts() throws Exception { 223 Nat464Xlat nat = makeNat464Xlat(); 224 225 // ConnectivityService starts clat. 226 nat.start(); 227 228 verify(mNms).registerObserver(eq(nat)); 229 verify(mNms).startClatd(eq(BASE_IFACE)); 230 231 // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...) 232 nat.stop(); 233 234 verify(mNms).unregisterObserver(eq(nat)); 235 verify(mNms).stopClatd(eq(BASE_IFACE)); 236 assertIdle(nat); 237 238 verifyNoMoreInteractions(mNms, mConnectivity); 239 } 240 assertIdle(Nat464Xlat nat)241 static void assertIdle(Nat464Xlat nat) { 242 assertTrue("Nat464Xlat was not IDLE", !nat.isStarted()); 243 } 244 assertRunning(Nat464Xlat nat)245 static void assertRunning(Nat464Xlat nat) { 246 assertTrue("Nat464Xlat was not RUNNING", nat.isRunning()); 247 } 248 } 249