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 android.net.dhcp;
18 
19 import static android.net.InetAddresses.parseNumericAddress;
20 import static android.net.dhcp.DhcpServingParams.MTU_UNSET;
21 
22 import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH;
23 
24 import static junit.framework.Assert.assertEquals;
25 import static junit.framework.Assert.assertFalse;
26 import static junit.framework.Assert.assertTrue;
27 
28 import android.annotation.NonNull;
29 import android.annotation.Nullable;
30 import android.net.LinkAddress;
31 import android.net.dhcp.DhcpServingParams.InvalidParameterException;
32 
33 import androidx.test.filters.SmallTest;
34 import androidx.test.runner.AndroidJUnit4;
35 
36 import com.android.net.module.util.Inet4AddressUtils;
37 import com.android.testutils.MiscAsserts;
38 
39 import org.junit.Before;
40 import org.junit.Test;
41 import org.junit.runner.RunWith;
42 
43 import java.net.Inet4Address;
44 import java.util.Arrays;
45 import java.util.Collection;
46 import java.util.HashSet;
47 import java.util.Set;
48 
49 @RunWith(AndroidJUnit4.class)
50 @SmallTest
51 public class DhcpServingParamsTest {
52     @NonNull
53     private DhcpServingParams.Builder mBuilder;
54 
55     private static final Set<Inet4Address> TEST_DEFAULT_ROUTERS = new HashSet<>(
56             Arrays.asList(parseAddr("192.168.0.123"), parseAddr("192.168.0.124")));
57     private static final long TEST_LEASE_TIME_SECS = 3600L;
58     private static final Set<Inet4Address> TEST_DNS_SERVERS = new HashSet<>(
59             Arrays.asList(parseAddr("192.168.0.126"), parseAddr("192.168.0.127")));
60     private static final Inet4Address TEST_SERVER_ADDR = parseAddr("192.168.0.2");
61     private static final Inet4Address TEST_CLIENT_ADDR = parseAddr("192.168.0.42");
62     private static final LinkAddress TEST_LINKADDR = new LinkAddress(TEST_SERVER_ADDR, 20);
63     private static final int TEST_MTU = 1500;
64     private static final Set<Inet4Address> TEST_EXCLUDED_ADDRS = new HashSet<>(
65             Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201")));
66     private static final boolean TEST_METERED = true;
67     private static final boolean TEST_CHANGE_PREFIX_ON_DECLINE = true;
68     private static final int LEASES_SUBNET_PREFIX_LENGTH = 25;
69 
70     @Before
setUp()71     public void setUp() {
72         mBuilder = new DhcpServingParams.Builder()
73                 .setDefaultRouters(TEST_DEFAULT_ROUTERS)
74                 .setDhcpLeaseTimeSecs(TEST_LEASE_TIME_SECS)
75                 .setDnsServers(TEST_DNS_SERVERS)
76                 .setServerAddr(TEST_LINKADDR)
77                 .setLinkMtu(TEST_MTU)
78                 .setExcludedAddrs(TEST_EXCLUDED_ADDRS)
79                 .setMetered(TEST_METERED)
80                 .setSingleClientAddr(TEST_CLIENT_ADDR)
81                 .setChangePrefixOnDecline(TEST_CHANGE_PREFIX_ON_DECLINE)
82                 .setLeasesSubnetPrefixLength(LEASES_SUBNET_PREFIX_LENGTH);
83     }
84 
85     @Test
testBuild_Immutable()86     public void testBuild_Immutable() throws InvalidParameterException {
87         final Set<Inet4Address> routers = new HashSet<>(TEST_DEFAULT_ROUTERS);
88         final Set<Inet4Address> dnsServers = new HashSet<>(TEST_DNS_SERVERS);
89         final Set<Inet4Address> excludedAddrs = new HashSet<>(TEST_EXCLUDED_ADDRS);
90 
91         final DhcpServingParams params = mBuilder
92                 .setDefaultRouters(routers)
93                 .setDnsServers(dnsServers)
94                 .setExcludedAddrs(excludedAddrs)
95                 .build();
96 
97         // Modifications to source objects should not affect builder or final parameters
98         final Inet4Address addedAddr = parseAddr("192.168.0.223");
99         routers.add(addedAddr);
100         dnsServers.add(addedAddr);
101         excludedAddrs.add(addedAddr);
102 
103         assertEquals(TEST_DEFAULT_ROUTERS, params.defaultRouters);
104         assertEquals(TEST_LEASE_TIME_SECS, params.dhcpLeaseTimeSecs);
105         assertEquals(TEST_DNS_SERVERS, params.dnsServers);
106         assertEquals(TEST_LINKADDR, params.serverAddr);
107         assertEquals(TEST_MTU, params.linkMtu);
108         assertEquals(TEST_METERED, params.metered);
109         assertEquals(TEST_CHANGE_PREFIX_ON_DECLINE, params.changePrefixOnDecline);
110 
111         assertContains(params.excludedAddrs, TEST_EXCLUDED_ADDRS);
112         assertContains(params.excludedAddrs, TEST_DEFAULT_ROUTERS);
113         assertContains(params.excludedAddrs, TEST_DNS_SERVERS);
114         assertContains(params.excludedAddrs, TEST_SERVER_ADDR);
115 
116         assertFalse("excludedAddrs should not contain " + addedAddr,
117                 params.excludedAddrs.contains(addedAddr));
118     }
119 
120     @Test(expected = InvalidParameterException.class)
testBuild_NegativeLeaseTime()121     public void testBuild_NegativeLeaseTime() throws InvalidParameterException {
122         mBuilder.setDhcpLeaseTimeSecs(-1).build();
123     }
124 
125     @Test(expected = InvalidParameterException.class)
testBuild_LeaseTimeTooLarge()126     public void testBuild_LeaseTimeTooLarge() throws InvalidParameterException {
127         // Set lease time larger than max value for uint32
128         mBuilder.setDhcpLeaseTimeSecs(1L << 32).build();
129     }
130 
131     @Test
testBuild_InfiniteLeaseTime()132     public void testBuild_InfiniteLeaseTime() throws InvalidParameterException {
133         final long infiniteLeaseTime = 0xffffffffL;
134         final DhcpServingParams params = mBuilder
135                 .setDhcpLeaseTimeSecs(infiniteLeaseTime).build();
136         assertEquals(infiniteLeaseTime, params.dhcpLeaseTimeSecs);
137         assertTrue(params.dhcpLeaseTimeSecs > 0L);
138     }
139 
140     @Test
testBuild_UnsetMtu()141     public void testBuild_UnsetMtu() throws InvalidParameterException {
142         final DhcpServingParams params = mBuilder.setLinkMtu(MTU_UNSET).build();
143         assertEquals(MTU_UNSET, params.linkMtu);
144     }
145 
146     @Test(expected = InvalidParameterException.class)
testBuild_MtuTooSmall()147     public void testBuild_MtuTooSmall() throws InvalidParameterException {
148         mBuilder.setLinkMtu(20).build();
149     }
150 
151     @Test(expected = InvalidParameterException.class)
testBuild_MtuTooLarge()152     public void testBuild_MtuTooLarge() throws InvalidParameterException {
153         mBuilder.setLinkMtu(65_536).build();
154     }
155 
156     @Test(expected = InvalidParameterException.class)
testBuild_IPv6Addr()157     public void testBuild_IPv6Addr() throws InvalidParameterException {
158         mBuilder.setServerAddr(new LinkAddress(parseNumericAddress("fe80::1111"), 120)).build();
159     }
160 
161     @Test(expected = InvalidParameterException.class)
testBuild_PrefixTooLarge()162     public void testBuild_PrefixTooLarge() throws InvalidParameterException {
163         mBuilder.setServerAddr(new LinkAddress(TEST_SERVER_ADDR, 15)).build();
164     }
165 
166     @Test(expected = InvalidParameterException.class)
testBuild_PrefixTooSmall()167     public void testBuild_PrefixTooSmall() throws InvalidParameterException {
168         mBuilder.setDefaultRouters(parseAddr("192.168.0.254"))
169                 .setServerAddr(new LinkAddress(TEST_SERVER_ADDR, 31))
170                 .build();
171     }
172 
173     @Test(expected = InvalidParameterException.class)
testBuild_RouterNotInPrefix()174     public void testBuild_RouterNotInPrefix() throws InvalidParameterException {
175         mBuilder.setDefaultRouters(parseAddr("192.168.254.254")).build();
176     }
177 
178     @Test
testBuild_LeasesSubnetPrefixLengthDefault()179     public void testBuild_LeasesSubnetPrefixLengthDefault() throws InvalidParameterException {
180         final DhcpServingParams params = mBuilder.setLeasesSubnetPrefixLength(0).build();
181         // Same as server address prefix length (20).
182         assertEquals(20, params.leasesSubnetPrefixLength);
183     }
184 
185     @Test(expected = InvalidParameterException.class)
testBuild_LeasesSubnetPrefixLengthTooSmall()186     public void testBuild_LeasesSubnetPrefixLengthTooSmall() throws InvalidParameterException {
187         // Smaller than server address prefix length (20).
188         mBuilder.setLeasesSubnetPrefixLength(2).build();
189     }
190 
191     @Test(expected = InvalidParameterException.class)
testBuild_LeasesSubnetPrefixLengthTooLarge()192     public void testBuild_LeasesSubnetPrefixLengthTooLarge() throws InvalidParameterException {
193         // Larger than max prefix length (30).
194         mBuilder.setLeasesSubnetPrefixLength(31).build();
195     }
196 
197     @Test
testFromParcelableObject()198     public void testFromParcelableObject() throws InvalidParameterException {
199         final DhcpServingParams params = mBuilder.build();
200         final DhcpServingParamsParcel parcel = new DhcpServingParamsParcel();
201         parcel.defaultRouters = toIntArray(TEST_DEFAULT_ROUTERS);
202         parcel.dhcpLeaseTimeSecs = TEST_LEASE_TIME_SECS;
203         parcel.dnsServers = toIntArray(TEST_DNS_SERVERS);
204         parcel.serverAddr = inet4AddressToIntHTH(TEST_SERVER_ADDR);
205         parcel.serverAddrPrefixLength = TEST_LINKADDR.getPrefixLength();
206         parcel.linkMtu = TEST_MTU;
207         parcel.excludedAddrs = toIntArray(TEST_EXCLUDED_ADDRS);
208         parcel.metered = TEST_METERED;
209         parcel.singleClientAddr = inet4AddressToIntHTH(TEST_CLIENT_ADDR);
210         parcel.changePrefixOnDecline = TEST_CHANGE_PREFIX_ON_DECLINE;
211         parcel.leasesSubnetPrefixLength = LEASES_SUBNET_PREFIX_LENGTH;
212         final DhcpServingParams parceled = DhcpServingParams.fromParcelableObject(parcel);
213 
214         assertEquals(params.defaultRouters, parceled.defaultRouters);
215         assertEquals(params.dhcpLeaseTimeSecs, parceled.dhcpLeaseTimeSecs);
216         assertEquals(params.dnsServers, parceled.dnsServers);
217         assertEquals(params.serverAddr, parceled.serverAddr);
218         assertEquals(params.linkMtu, parceled.linkMtu);
219         assertEquals(params.excludedAddrs, parceled.excludedAddrs);
220         assertEquals(params.metered, parceled.metered);
221         assertEquals(params.singleClientAddr, parceled.singleClientAddr);
222         assertEquals(params.changePrefixOnDecline, parceled.changePrefixOnDecline);
223         assertEquals(params.leasesSubnetPrefixLength, parceled.leasesSubnetPrefixLength);
224 
225         MiscAsserts.assertFieldCountEquals(11, DhcpServingParamsParcel.class);
226     }
227 
228     @Test(expected = InvalidParameterException.class)
testFromParcelableObject_NullArgument()229     public void testFromParcelableObject_NullArgument() throws InvalidParameterException {
230         DhcpServingParams.fromParcelableObject(null);
231     }
232 
toIntArray(Collection<Inet4Address> addrs)233     private static int[] toIntArray(Collection<Inet4Address> addrs) {
234         return addrs.stream().mapToInt(Inet4AddressUtils::inet4AddressToIntHTH).toArray();
235     }
236 
assertContains(@onNull Set<T> set, @NonNull Set<T> subset)237     private static <T> void assertContains(@NonNull Set<T> set, @NonNull Set<T> subset) {
238         for (final T elem : subset) {
239             assertContains(set, elem);
240         }
241     }
242 
assertContains(@onNull Set<T> set, @Nullable T elem)243     private static <T> void assertContains(@NonNull Set<T> set, @Nullable T elem) {
244         assertTrue("Set does not contain " + elem, set.contains(elem));
245     }
246 
247     @NonNull
parseAddr(@onNull String inet4Addr)248     private static Inet4Address parseAddr(@NonNull String inet4Addr) {
249         return (Inet4Address) parseNumericAddress(inet4Addr);
250     }
251 }
252