1 /*
2  * Copyright (C) 2020 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;
18 
19 import static android.net.InetAddresses.parseNumericAddress;
20 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
21 import static android.net.TetheringManager.TETHERING_ETHERNET;
22 import static android.net.TetheringTester.TestDnsPacket;
23 import static android.net.TetheringTester.buildIcmpEchoPacketV4;
24 import static android.net.TetheringTester.buildUdpPacket;
25 import static android.net.TetheringTester.isExpectedIcmpPacket;
26 import static android.net.TetheringTester.isExpectedUdpDnsPacket;
27 import static android.system.OsConstants.ICMP_ECHO;
28 import static android.system.OsConstants.ICMP_ECHOREPLY;
29 
30 import static com.android.net.module.util.ConnectivityUtils.isIPv6ULA;
31 import static com.android.net.module.util.HexDump.dumpHexString;
32 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REPLY_TYPE;
33 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
34 
35 import static org.junit.Assert.assertEquals;
36 import static org.junit.Assert.assertNotNull;
37 import static org.junit.Assert.assertTrue;
38 import static org.junit.Assert.fail;
39 import static org.junit.Assume.assumeFalse;
40 import static org.junit.Assume.assumeTrue;
41 
42 import android.net.TetheringManager.TetheringRequest;
43 import android.net.TetheringTester.TetheredDevice;
44 import android.os.Build;
45 import android.os.SystemClock;
46 import android.os.SystemProperties;
47 import android.util.Log;
48 
49 import androidx.annotation.NonNull;
50 import androidx.test.filters.LargeTest;
51 import androidx.test.runner.AndroidJUnit4;
52 
53 import com.android.net.module.util.Ipv6Utils;
54 import com.android.net.module.util.Struct;
55 import com.android.net.module.util.structs.Ipv4Header;
56 import com.android.net.module.util.structs.UdpHeader;
57 import com.android.testutils.DevSdkIgnoreRule;
58 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
59 import com.android.testutils.NetworkStackModuleTest;
60 import com.android.testutils.TapPacketReader;
61 
62 import org.junit.BeforeClass;
63 import org.junit.Rule;
64 import org.junit.Test;
65 import org.junit.runner.RunWith;
66 
67 import java.io.FileDescriptor;
68 import java.net.Inet4Address;
69 import java.net.Inet6Address;
70 import java.net.InetAddress;
71 import java.net.InterfaceAddress;
72 import java.net.NetworkInterface;
73 import java.nio.ByteBuffer;
74 import java.util.Arrays;
75 import java.util.Collection;
76 import java.util.List;
77 import java.util.Random;
78 import java.util.concurrent.CompletableFuture;
79 import java.util.concurrent.TimeUnit;
80 import java.util.concurrent.TimeoutException;
81 
82 @RunWith(AndroidJUnit4.class)
83 @LargeTest
84 public class EthernetTetheringTest extends EthernetTetheringTestBase {
85     @Rule
86     public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
87 
88     private static final String TAG = EthernetTetheringTest.class.getSimpleName();
89 
90     private static final short DNS_PORT = 53;
91     private static final short ICMPECHO_ID = 0x0;
92     private static final short ICMPECHO_SEQ = 0x0;
93 
94     // TODO: use class DnsPacket to build DNS query and reply message once DnsPacket supports
95     // building packet for given arguments.
96     private static final ByteBuffer DNS_QUERY = ByteBuffer.wrap(new byte[] {
97             // scapy.DNS(
98             //   id=0xbeef,
99             //   qr=0,
100             //   qd=scapy.DNSQR(qname="hello.example.com"))
101             //
102             /* Header */
103             (byte) 0xbe, (byte) 0xef, /* Transaction ID: 0xbeef */
104             (byte) 0x01, (byte) 0x00, /* Flags: rd */
105             (byte) 0x00, (byte) 0x01, /* Questions: 1 */
106             (byte) 0x00, (byte) 0x00, /* Answer RRs: 0 */
107             (byte) 0x00, (byte) 0x00, /* Authority RRs: 0 */
108             (byte) 0x00, (byte) 0x00, /* Additional RRs: 0 */
109             /* Queries */
110             (byte) 0x05, (byte) 0x68, (byte) 0x65, (byte) 0x6c,
111             (byte) 0x6c, (byte) 0x6f, (byte) 0x07, (byte) 0x65,
112             (byte) 0x78, (byte) 0x61, (byte) 0x6d, (byte) 0x70,
113             (byte) 0x6c, (byte) 0x65, (byte) 0x03, (byte) 0x63,
114             (byte) 0x6f, (byte) 0x6d, (byte) 0x00, /* Name: hello.example.com */
115             (byte) 0x00, (byte) 0x01,              /* Type: A */
116             (byte) 0x00, (byte) 0x01               /* Class: IN */
117     });
118 
119     private static final byte[] DNS_REPLY = new byte[] {
120             // scapy.DNS(
121             //   id=0,
122             //   qr=1,
123             //   qd=scapy.DNSQR(qname="hello.example.com"),
124             //   an=scapy.DNSRR(rrname="hello.example.com", rdata='1.2.3.4'))
125             //
126             /* Header */
127             (byte) 0x00, (byte) 0x00, /* Transaction ID: 0x0, must be updated by dns query id */
128             (byte) 0x81, (byte) 0x00, /* Flags: qr rd */
129             (byte) 0x00, (byte) 0x01, /* Questions: 1 */
130             (byte) 0x00, (byte) 0x01, /* Answer RRs: 1 */
131             (byte) 0x00, (byte) 0x00, /* Authority RRs: 0 */
132             (byte) 0x00, (byte) 0x00, /* Additional RRs: 0 */
133             /* Queries */
134             (byte) 0x05, (byte) 0x68, (byte) 0x65, (byte) 0x6c,
135             (byte) 0x6c, (byte) 0x6f, (byte) 0x07, (byte) 0x65,
136             (byte) 0x78, (byte) 0x61, (byte) 0x6d, (byte) 0x70,
137             (byte) 0x6c, (byte) 0x65, (byte) 0x03, (byte) 0x63,
138             (byte) 0x6f, (byte) 0x6d, (byte) 0x00,              /* Name: hello.example.com */
139             (byte) 0x00, (byte) 0x01,                           /* Type: A */
140             (byte) 0x00, (byte) 0x01,                           /* Class: IN */
141             /* Answers */
142             (byte) 0x05, (byte) 0x68, (byte) 0x65, (byte) 0x6c,
143             (byte) 0x6c, (byte) 0x6f, (byte) 0x07, (byte) 0x65,
144             (byte) 0x78, (byte) 0x61, (byte) 0x6d, (byte) 0x70,
145             (byte) 0x6c, (byte) 0x65, (byte) 0x03, (byte) 0x63,
146             (byte) 0x6f, (byte) 0x6d, (byte) 0x00,              /* Name: hello.example.com */
147             (byte) 0x00, (byte) 0x01,                           /* Type: A */
148             (byte) 0x00, (byte) 0x01,                           /* Class: IN */
149             (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, /* Time to live: 0 */
150             (byte) 0x00, (byte) 0x04,                           /* Data length: 4 */
151             (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04  /* Address: 1.2.3.4 */
152     };
153 
154     /** Enable/disable tethering once before running the tests. */
155     @BeforeClass
setUpOnce()156     public static void setUpOnce() throws Exception {
157         // The first test case may experience tethering restart with IP conflict handling.
158         // Tethering would cache the last upstreams so that the next enabled tethering avoids
159         // picking up the address that is in conflict with the upstreams. To protect subsequent
160         // tests, turn tethering on and off before running them.
161         MyTetheringEventCallback callback = null;
162         TestNetworkInterface testIface = null;
163         assumeTrue(sEm != null);
164         try {
165             // If the physical ethernet interface is available, do nothing.
166             if (isInterfaceForTetheringAvailable()) return;
167 
168             testIface = createTestInterface();
169             setIncludeTestInterfaces(true);
170 
171             callback = enableEthernetTethering(testIface.getInterfaceName(), null);
172             callback.awaitUpstreamChanged(true /* throwTimeoutException */);
173         } catch (TimeoutException e) {
174             Log.d(TAG, "WARNNING " + e);
175         } finally {
176             maybeCloseTestInterface(testIface);
177             maybeUnregisterTetheringEventCallback(callback);
178 
179             setIncludeTestInterfaces(false);
180         }
181     }
182 
183     @Test
testVirtualEthernetAlreadyExists()184     public void testVirtualEthernetAlreadyExists() throws Exception {
185         // This test requires manipulating packets. Skip if there is a physical Ethernet connected.
186         assumeFalse(isInterfaceForTetheringAvailable());
187 
188         TestNetworkInterface downstreamIface = null;
189         MyTetheringEventCallback tetheringEventCallback = null;
190         TapPacketReader downstreamReader = null;
191 
192         try {
193             downstreamIface = createTestInterface();
194             // This must be done now because as soon as setIncludeTestInterfaces(true) is called,
195             // the interface will be placed in client mode, which will delete the link-local
196             // address. At that point NetworkInterface.getByName() will cease to work on the
197             // interface, because starting in R NetworkInterface can no longer see interfaces
198             // without IP addresses.
199             int mtu = getMTU(downstreamIface);
200 
201             Log.d(TAG, "Including test interfaces");
202             setIncludeTestInterfaces(true);
203 
204             final String iface = getTetheredInterface();
205             assertEquals("TetheredInterfaceCallback for unexpected interface",
206                     downstreamIface.getInterfaceName(), iface);
207 
208             // Check virtual ethernet.
209             FileDescriptor fd = downstreamIface.getFileDescriptor().getFileDescriptor();
210             downstreamReader = makePacketReader(fd, mtu);
211             tetheringEventCallback = enableEthernetTethering(downstreamIface.getInterfaceName(),
212                     null /* any upstream */);
213             checkTetheredClientCallbacks(downstreamReader, tetheringEventCallback);
214         } finally {
215             maybeStopTapPacketReader(downstreamReader);
216             maybeCloseTestInterface(downstreamIface);
217             maybeUnregisterTetheringEventCallback(tetheringEventCallback);
218         }
219     }
220 
221     @Test
testVirtualEthernet()222     public void testVirtualEthernet() throws Exception {
223         // This test requires manipulating packets. Skip if there is a physical Ethernet connected.
224         assumeFalse(isInterfaceForTetheringAvailable());
225 
226         CompletableFuture<String> futureIface = requestTetheredInterface();
227 
228         setIncludeTestInterfaces(true);
229 
230         TestNetworkInterface downstreamIface = null;
231         MyTetheringEventCallback tetheringEventCallback = null;
232         TapPacketReader downstreamReader = null;
233 
234         try {
235             downstreamIface = createTestInterface();
236 
237             final String iface = futureIface.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
238             assertEquals("TetheredInterfaceCallback for unexpected interface",
239                     downstreamIface.getInterfaceName(), iface);
240 
241             // Check virtual ethernet.
242             FileDescriptor fd = downstreamIface.getFileDescriptor().getFileDescriptor();
243             downstreamReader = makePacketReader(fd, getMTU(downstreamIface));
244             tetheringEventCallback = enableEthernetTethering(downstreamIface.getInterfaceName(),
245                     null /* any upstream */);
246             checkTetheredClientCallbacks(downstreamReader, tetheringEventCallback);
247         } finally {
248             maybeStopTapPacketReader(downstreamReader);
249             maybeCloseTestInterface(downstreamIface);
250             maybeUnregisterTetheringEventCallback(tetheringEventCallback);
251         }
252     }
253 
254     @Test
testStaticIpv4()255     public void testStaticIpv4() throws Exception {
256         assumeFalse(isInterfaceForTetheringAvailable());
257 
258         setIncludeTestInterfaces(true);
259 
260         TestNetworkInterface downstreamIface = null;
261         MyTetheringEventCallback tetheringEventCallback = null;
262         TapPacketReader downstreamReader = null;
263 
264         try {
265             downstreamIface = createTestInterface();
266 
267             final String iface = getTetheredInterface();
268             assertEquals("TetheredInterfaceCallback for unexpected interface",
269                     downstreamIface.getInterfaceName(), iface);
270 
271             assertInvalidStaticIpv4Request(iface, null, null);
272             assertInvalidStaticIpv4Request(iface, "2001:db8::1/64", "2001:db8:2::/64");
273             assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", "2001:db8:2::/28");
274             assertInvalidStaticIpv4Request(iface, "2001:db8:2::/28", "192.0.2.2/28");
275             assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", null);
276             assertInvalidStaticIpv4Request(iface, null, "192.0.2.2/28");
277             assertInvalidStaticIpv4Request(iface, "192.0.2.3/27", "192.0.2.2/28");
278 
279             final String localAddr = "192.0.2.3/28";
280             final String clientAddr = "192.0.2.2/28";
281             tetheringEventCallback = enableEthernetTethering(iface,
282                     requestWithStaticIpv4(localAddr, clientAddr), null /* any upstream */);
283 
284             tetheringEventCallback.awaitInterfaceTethered();
285             assertInterfaceHasIpAddress(iface, localAddr);
286 
287             byte[] client1 = MacAddress.fromString("1:2:3:4:5:6").toByteArray();
288             byte[] client2 = MacAddress.fromString("a:b:c:d:e:f").toByteArray();
289 
290             FileDescriptor fd = downstreamIface.getFileDescriptor().getFileDescriptor();
291             downstreamReader = makePacketReader(fd, getMTU(downstreamIface));
292             TetheringTester tester = new TetheringTester(downstreamReader);
293             DhcpResults dhcpResults = tester.runDhcp(client1);
294             assertEquals(new LinkAddress(clientAddr), dhcpResults.ipAddress);
295 
296             try {
297                 tester.runDhcp(client2);
298                 fail("Only one client should get an IP address");
299             } catch (TimeoutException expected) { }
300         } finally {
301             maybeStopTapPacketReader(downstreamReader);
302             maybeCloseTestInterface(downstreamIface);
303             maybeUnregisterTetheringEventCallback(tetheringEventCallback);
304         }
305     }
306 
expectLocalOnlyAddresses(String iface)307     private static void expectLocalOnlyAddresses(String iface) throws Exception {
308         final List<InterfaceAddress> interfaceAddresses =
309                 NetworkInterface.getByName(iface).getInterfaceAddresses();
310 
311         boolean foundIpv6Ula = false;
312         for (InterfaceAddress ia : interfaceAddresses) {
313             final InetAddress addr = ia.getAddress();
314             if (isIPv6ULA(addr)) {
315                 foundIpv6Ula = true;
316             }
317             final int prefixlen = ia.getNetworkPrefixLength();
318             final LinkAddress la = new LinkAddress(addr, prefixlen);
319             if (la.isIpv6() && la.isGlobalPreferred()) {
320                 fail("Found global IPv6 address on local-only interface: " + interfaceAddresses);
321             }
322         }
323 
324         assertTrue("Did not find IPv6 ULA on local-only interface " + iface,
325                 foundIpv6Ula);
326     }
327 
328     @Test
testLocalOnlyTethering()329     public void testLocalOnlyTethering() throws Exception {
330         assumeFalse(isInterfaceForTetheringAvailable());
331 
332         setIncludeTestInterfaces(true);
333 
334         TestNetworkInterface downstreamIface = null;
335         MyTetheringEventCallback tetheringEventCallback = null;
336         TapPacketReader downstreamReader = null;
337 
338         try {
339             downstreamIface = createTestInterface();
340 
341             final String iface = getTetheredInterface();
342             assertEquals("TetheredInterfaceCallback for unexpected interface",
343                     downstreamIface.getInterfaceName(), iface);
344 
345             final TetheringRequest request = new TetheringRequest.Builder(TETHERING_ETHERNET)
346                     .setConnectivityScope(CONNECTIVITY_SCOPE_LOCAL).build();
347             tetheringEventCallback = enableEthernetTethering(iface, request,
348                     null /* any upstream */);
349             tetheringEventCallback.awaitInterfaceLocalOnly();
350 
351             // makePacketReader only works after tethering is started, because until then the
352             // interface does not have an IP address, and unprivileged apps cannot see interfaces
353             // without IP addresses. This shouldn't be flaky because the TAP interface will buffer
354             // all packets even before the reader is started.
355             downstreamReader = makePacketReader(downstreamIface);
356 
357             waitForRouterAdvertisement(downstreamReader, iface, WAIT_RA_TIMEOUT_MS);
358             expectLocalOnlyAddresses(iface);
359 
360             // After testing the IPv6 local address, the DHCP server may still be in the process
361             // of being created. If the downstream interface is killed by the test while the
362             // DHCP server is starting, a DHCP server error may occur. To ensure that the DHCP
363             // server has started completely before finishing the test, also test the dhcp server
364             // by calling runDhcp.
365             final TetheringTester tester = new TetheringTester(downstreamReader);
366             tester.runDhcp(MacAddress.fromString("1:2:3:4:5:6").toByteArray());
367         } finally {
368             maybeStopTapPacketReader(downstreamReader);
369             maybeCloseTestInterface(downstreamIface);
370             maybeUnregisterTetheringEventCallback(tetheringEventCallback);
371         }
372     }
373 
isAdbOverNetwork()374     private boolean isAdbOverNetwork() {
375         // If adb TCP port opened, this test may running by adb over network.
376         return (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1)
377                 || (SystemProperties.getInt("service.adb.tcp.port", -1) > -1);
378     }
379 
380     @Test
testPhysicalEthernet()381     public void testPhysicalEthernet() throws Exception {
382         assumeTrue(isInterfaceForTetheringAvailable());
383         // Do not run this test if adb is over network and ethernet is connected.
384         // It is likely the adb run over ethernet, the adb would break when ethernet is switching
385         // from client mode to server mode. See b/160389275.
386         assumeFalse(isAdbOverNetwork());
387 
388         MyTetheringEventCallback tetheringEventCallback = null;
389         try {
390             // Get an interface to use.
391             final String iface = getTetheredInterface();
392 
393             // Enable Ethernet tethering and check that it starts.
394             tetheringEventCallback = enableEthernetTethering(iface, null /* any upstream */);
395         } finally {
396             stopEthernetTethering(tetheringEventCallback);
397         }
398         // There is nothing more we can do on a physical interface without connecting an actual
399         // client, which is not possible in this test.
400     }
401 
checkTetheredClientCallbacks(final TapPacketReader packetReader, final MyTetheringEventCallback tetheringEventCallback)402     private void checkTetheredClientCallbacks(final TapPacketReader packetReader,
403             final MyTetheringEventCallback tetheringEventCallback) throws Exception {
404         // Create a fake client.
405         byte[] clientMacAddr = new byte[6];
406         new Random().nextBytes(clientMacAddr);
407 
408         TetheringTester tester = new TetheringTester(packetReader);
409         DhcpResults dhcpResults = tester.runDhcp(clientMacAddr);
410 
411         final Collection<TetheredClient> clients = tetheringEventCallback.awaitClientConnected();
412         assertEquals(1, clients.size());
413         final TetheredClient client = clients.iterator().next();
414 
415         // Check the MAC address.
416         assertEquals(MacAddress.fromBytes(clientMacAddr), client.getMacAddress());
417         assertEquals(TETHERING_ETHERNET, client.getTetheringType());
418 
419         // Check the hostname.
420         assertEquals(1, client.getAddresses().size());
421         TetheredClient.AddressInfo info = client.getAddresses().get(0);
422         assertEquals(TetheringTester.DHCP_HOSTNAME, info.getHostname());
423 
424         // Check the address is the one that was handed out in the DHCP ACK.
425         assertLinkAddressMatches(dhcpResults.ipAddress, info.getAddress());
426 
427         // Check that the lifetime is correct +/- 10s.
428         final long now = SystemClock.elapsedRealtime();
429         final long actualLeaseDuration = (info.getAddress().getExpirationTime() - now) / 1000;
430         final String msg = String.format("IP address should have lifetime of %d, got %d",
431                 dhcpResults.leaseDuration, actualLeaseDuration);
432         assertTrue(msg, Math.abs(dhcpResults.leaseDuration - actualLeaseDuration) < 10);
433     }
434 
assertLinkAddressMatches(LinkAddress l1, LinkAddress l2)435     public void assertLinkAddressMatches(LinkAddress l1, LinkAddress l2) {
436         // Check all fields except the deprecation and expiry times.
437         String msg = String.format("LinkAddresses do not match. expected: %s actual: %s", l1, l2);
438         assertTrue(msg, l1.isSameAddressAs(l2));
439         assertEquals("LinkAddress flags do not match", l1.getFlags(), l2.getFlags());
440         assertEquals("LinkAddress scope does not match", l1.getScope(), l2.getScope());
441     }
442 
requestWithStaticIpv4(String local, String client)443     private TetheringRequest requestWithStaticIpv4(String local, String client) {
444         LinkAddress localAddr = local == null ? null : new LinkAddress(local);
445         LinkAddress clientAddr = client == null ? null : new LinkAddress(client);
446         return new TetheringRequest.Builder(TETHERING_ETHERNET)
447                 .setStaticIpv4Addresses(localAddr, clientAddr)
448                 .setShouldShowEntitlementUi(false).build();
449     }
450 
assertInvalidStaticIpv4Request(String iface, String local, String client)451     private void assertInvalidStaticIpv4Request(String iface, String local, String client)
452             throws Exception {
453         try {
454             enableEthernetTethering(iface, requestWithStaticIpv4(local, client),
455                     null /* any upstream */);
456             fail("Unexpectedly accepted invalid IPv4 configuration: " + local + ", " + client);
457         } catch (IllegalArgumentException | NullPointerException expected) { }
458     }
459 
assertInterfaceHasIpAddress(String iface, String expected)460     private void assertInterfaceHasIpAddress(String iface, String expected) throws Exception {
461         LinkAddress expectedAddr = new LinkAddress(expected);
462         NetworkInterface nif = NetworkInterface.getByName(iface);
463         for (InterfaceAddress ia : nif.getInterfaceAddresses()) {
464             final LinkAddress addr = new LinkAddress(ia.getAddress(), ia.getNetworkPrefixLength());
465             if (expectedAddr.equals(addr)) {
466                 return;
467             }
468         }
469         fail("Expected " + iface + " to have IP address " + expected + ", found "
470                 + nif.getInterfaceAddresses());
471     }
472 
473     @Test
testIcmpv6Echo()474     public void testIcmpv6Echo() throws Exception {
475         runPing6Test(initTetheringTester(toList(TEST_IP4_ADDR, TEST_IP6_ADDR),
476                 toList(TEST_IP4_DNS, TEST_IP6_DNS)));
477     }
478 
runPing6Test(TetheringTester tester)479     private void runPing6Test(TetheringTester tester) throws Exception {
480         TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, true /* hasIpv6 */);
481         Inet6Address remoteIp6Addr = (Inet6Address) parseNumericAddress("2400:222:222::222");
482         ByteBuffer request = Ipv6Utils.buildEchoRequestPacket(tethered.macAddr,
483                 tethered.routerMacAddr, tethered.ipv6Addr, remoteIp6Addr);
484         tester.verifyUpload(request, p -> {
485             Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
486 
487             return isExpectedIcmpPacket(p, false /* hasEth */, false /* isIpv4 */,
488                     ICMPV6_ECHO_REQUEST_TYPE);
489         });
490 
491         ByteBuffer reply = Ipv6Utils.buildEchoReplyPacket(remoteIp6Addr, tethered.ipv6Addr);
492         tester.verifyDownload(reply, p -> {
493             Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
494 
495             return isExpectedIcmpPacket(p, true /* hasEth */, false /* isIpv4 */,
496                     ICMPV6_ECHO_REPLY_TYPE);
497         });
498     }
499 
500     @Test
testTetherUdpV6()501     public void testTetherUdpV6() throws Exception {
502         final TetheringTester tester = initTetheringTester(toList(TEST_IP6_ADDR),
503                 toList(TEST_IP6_DNS));
504         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, true /* hasIpv6 */);
505         sendUploadPacketUdp(tethered.macAddr, tethered.routerMacAddr,
506                 tethered.ipv6Addr, REMOTE_IP6_ADDR, tester, false /* is4To6 */);
507         sendDownloadPacketUdp(REMOTE_IP6_ADDR, tethered.ipv6Addr, tester, false /* is6To4 */);
508 
509         // TODO: test BPF offload maps {rule, stats}.
510     }
511 
512     // Test network topology:
513     //
514     //         public network (rawip)                 private network
515     //                   |                 UE                |
516     // +------------+    V    +------------+------------+    V    +------------+
517     // |   Sever    +---------+  Upstream  | Downstream +---------+   Client   |
518     // +------------+         +------------+------------+         +------------+
519     // remote ip              public ip                           private ip
520     // 8.8.8.8:443            <Upstream ip>:9876                  <TetheredDevice ip>:9876
521     //
runUdp4Test()522     private void runUdp4Test() throws Exception {
523         final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
524                 toList(TEST_IP4_DNS));
525         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
526 
527         // TODO: remove the connectivity verification for upstream connected notification race.
528         // Because async upstream connected notification can't guarantee the tethering routing is
529         // ready to use. Need to test tethering connectivity before testing.
530         // For short term plan, consider using IPv6 RA to get MAC address because the prefix comes
531         // from upstream. That can guarantee that the routing is ready. Long term plan is that
532         // refactors upstream connected notification from async to sync.
533         probeV4TetheringConnectivity(tester, tethered, false /* is4To6 */);
534 
535         final MacAddress srcMac = tethered.macAddr;
536         final MacAddress dstMac = tethered.routerMacAddr;
537         final InetAddress remoteIp = REMOTE_IP4_ADDR;
538         final InetAddress tetheringUpstreamIp = TEST_IP4_ADDR.getAddress();
539         final InetAddress clientIp = tethered.ipv4Addr;
540         sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */);
541         sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */);
542     }
543 
544     /**
545      * Basic IPv4 UDP tethering test. Verify that UDP tethered packets are transferred no matter
546      * using which data path.
547      */
548     @Test
testTetherUdpV4()549     public void testTetherUdpV4() throws Exception {
550         runUdp4Test();
551     }
552 
553     // Test network topology:
554     //
555     //            public network (rawip)                 private network
556     //                      |         UE (CLAT support)         |
557     // +---------------+    V    +------------+------------+    V    +------------+
558     // | NAT64 Gateway +---------+  Upstream  | Downstream +---------+   Client   |
559     // +---------------+         +------------+------------+         +------------+
560     // remote ip                 public ip                           private ip
561     // [64:ff9b::808:808]:443    [clat ipv6]:9876                    [TetheredDevice ipv4]:9876
562     //
563     // Note that CLAT IPv6 address is generated by ClatCoordinator. Get the CLAT IPv6 address by
564     // sending out an IPv4 packet and extracting the source address from CLAT translated IPv6
565     // packet.
566     //
runClatUdpTest()567     private void runClatUdpTest() throws Exception {
568         // CLAT only starts on IPv6 only network.
569         final TetheringTester tester = initTetheringTester(toList(TEST_IP6_ADDR),
570                 toList(TEST_IP6_DNS));
571         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, true /* hasIpv6 */);
572 
573         // Get CLAT IPv6 address.
574         final Inet6Address clatIp6 = getClatIpv6Address(tester, tethered);
575 
576         // Send an IPv4 UDP packet in original direction.
577         // IPv4 packet -- CLAT translation --> IPv6 packet
578         sendUploadPacketUdp(tethered.macAddr, tethered.routerMacAddr, tethered.ipv4Addr,
579                 REMOTE_IP4_ADDR, tester, true /* is4To6 */);
580 
581         // Send an IPv6 UDP packet in reply direction.
582         // IPv6 packet -- CLAT translation --> IPv4 packet
583         sendDownloadPacketUdp(REMOTE_NAT64_ADDR, clatIp6, tester, true /* is6To4 */);
584 
585         // TODO: test CLAT bpf maps.
586     }
587 
588     // TODO: support R device. See b/234727688.
589     @Test
590     @IgnoreUpTo(Build.VERSION_CODES.R)
testTetherClatUdp()591     public void testTetherClatUdp() throws Exception {
592         runClatUdpTest();
593     }
594 
595     @Test
testIcmpv4Echo()596     public void testIcmpv4Echo() throws Exception {
597         final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
598                 toList(TEST_IP4_DNS));
599         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
600 
601         // TODO: remove the connectivity verification for upstream connected notification race.
602         // See the same reason in runUdp4Test().
603         probeV4TetheringConnectivity(tester, tethered, false /* is4To6 */);
604 
605         final ByteBuffer request = buildIcmpEchoPacketV4(tethered.macAddr /* srcMac */,
606                 tethered.routerMacAddr /* dstMac */, tethered.ipv4Addr /* srcIp */,
607                 REMOTE_IP4_ADDR /* dstIp */, ICMP_ECHO, ICMPECHO_ID, ICMPECHO_SEQ);
608         tester.verifyUpload(request, p -> {
609             Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
610 
611             return isExpectedIcmpPacket(p, false /* hasEth */, true /* isIpv4 */, ICMP_ECHO);
612         });
613 
614         final ByteBuffer reply = buildIcmpEchoPacketV4(REMOTE_IP4_ADDR /* srcIp*/,
615                 (Inet4Address) TEST_IP4_ADDR.getAddress() /* dstIp */, ICMP_ECHOREPLY, ICMPECHO_ID,
616                 ICMPECHO_SEQ);
617         tester.verifyDownload(reply, p -> {
618             Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
619 
620             return isExpectedIcmpPacket(p, true /* hasEth */, true /* isIpv4 */, ICMP_ECHOREPLY);
621         });
622     }
623 
624     // TODO: support R device. See b/234727688.
625     @Test
626     @IgnoreUpTo(Build.VERSION_CODES.R)
testTetherClatIcmp()627     public void testTetherClatIcmp() throws Exception {
628         // CLAT only starts on IPv6 only network.
629         final TetheringTester tester = initTetheringTester(toList(TEST_IP6_ADDR),
630                 toList(TEST_IP6_DNS));
631         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, true /* hasIpv6 */);
632 
633         // Get CLAT IPv6 address.
634         final Inet6Address clatIp6 = getClatIpv6Address(tester, tethered);
635 
636         // Send an IPv4 ICMP packet in original direction.
637         // IPv4 packet -- CLAT translation --> IPv6 packet
638         final ByteBuffer request = buildIcmpEchoPacketV4(tethered.macAddr /* srcMac */,
639                 tethered.routerMacAddr /* dstMac */, tethered.ipv4Addr /* srcIp */,
640                 (Inet4Address) REMOTE_IP4_ADDR /* dstIp */, ICMP_ECHO, ICMPECHO_ID, ICMPECHO_SEQ);
641         tester.verifyUpload(request, p -> {
642             Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
643 
644             return isExpectedIcmpPacket(p, false /* hasEth */, false /* isIpv4 */,
645                     ICMPV6_ECHO_REQUEST_TYPE);
646         });
647 
648         // Send an IPv6 ICMP packet in reply direction.
649         // IPv6 packet -- CLAT translation --> IPv4 packet
650         final ByteBuffer reply = Ipv6Utils.buildEchoReplyPacket(
651                 (Inet6Address) REMOTE_NAT64_ADDR /* srcIp */, clatIp6 /* dstIp */);
652         tester.verifyDownload(reply, p -> {
653             Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
654 
655             return isExpectedIcmpPacket(p, true /* hasEth */, true /* isIpv4 */, ICMP_ECHOREPLY);
656         });
657     }
658 
659     @NonNull
buildDnsReplyMessageById(short id)660     private ByteBuffer buildDnsReplyMessageById(short id) {
661         byte[] replyMessage = Arrays.copyOf(DNS_REPLY, DNS_REPLY.length);
662         // Assign transaction id of reply message pattern with a given DNS transaction id.
663         replyMessage[0] = (byte) ((id >> 8) & 0xff);
664         replyMessage[1] = (byte) (id & 0xff);
665         Log.d(TAG, "Built DNS reply: " + dumpHexString(replyMessage));
666 
667         return ByteBuffer.wrap(replyMessage);
668     }
669 
670     @NonNull
sendDownloadPacketDnsV4(@onNull final Inet4Address srcIp, @NonNull final Inet4Address dstIp, short srcPort, short dstPort, short dnsId, @NonNull final TetheringTester tester)671     private void sendDownloadPacketDnsV4(@NonNull final Inet4Address srcIp,
672             @NonNull final Inet4Address dstIp, short srcPort, short dstPort, short dnsId,
673             @NonNull final TetheringTester tester) throws Exception {
674         // DNS response transaction id must be copied from DNS query. Used by the requester
675         // to match up replies to outstanding queries. See RFC 1035 section 4.1.1.
676         final ByteBuffer dnsReplyMessage = buildDnsReplyMessageById(dnsId);
677         final ByteBuffer testPacket = buildUdpPacket((InetAddress) srcIp,
678                 (InetAddress) dstIp, srcPort, dstPort, dnsReplyMessage);
679 
680         tester.verifyDownload(testPacket, p -> {
681             Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
682             return isExpectedUdpDnsPacket(p, true /* hasEther */, true /* isIpv4 */,
683                     dnsReplyMessage);
684         });
685     }
686 
687     // Send IPv4 UDP DNS packet and return the forwarded DNS packet on upstream.
688     @NonNull
sendUploadPacketDnsV4(@onNull final MacAddress srcMac, @NonNull final MacAddress dstMac, @NonNull final Inet4Address srcIp, @NonNull final Inet4Address dstIp, short srcPort, short dstPort, @NonNull final TetheringTester tester)689     private byte[] sendUploadPacketDnsV4(@NonNull final MacAddress srcMac,
690             @NonNull final MacAddress dstMac, @NonNull final Inet4Address srcIp,
691             @NonNull final Inet4Address dstIp, short srcPort, short dstPort,
692             @NonNull final TetheringTester tester) throws Exception {
693         final ByteBuffer testPacket = buildUdpPacket(srcMac, dstMac, srcIp, dstIp,
694                 srcPort, dstPort, DNS_QUERY);
695 
696         return tester.verifyUpload(testPacket, p -> {
697             Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
698             return isExpectedUdpDnsPacket(p, false /* hasEther */, true /* isIpv4 */,
699                     DNS_QUERY);
700         });
701     }
702 
703     @Test
testTetherUdpV4Dns()704     public void testTetherUdpV4Dns() throws Exception {
705         final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
706                 toList(TEST_IP4_DNS));
707         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
708 
709         // TODO: remove the connectivity verification for upstream connected notification race.
710         // See the same reason in runUdp4Test().
711         probeV4TetheringConnectivity(tester, tethered, false /* is4To6 */);
712 
713         // [1] Send DNS query.
714         // tethered device --> downstream --> dnsmasq forwarding --> upstream --> DNS server
715         //
716         // Need to extract DNS transaction id and source port from dnsmasq forwarded DNS query
717         // packet. dnsmasq forwarding creats new query which means UDP source port and DNS
718         // transaction id are changed from original sent DNS query. See forward_query() in
719         // external/dnsmasq/src/forward.c. Note that #TetheringTester.isExpectedUdpDnsPacket
720         // guarantees that |forwardedQueryPacket| is a valid DNS packet. So we can parse it as DNS
721         // packet.
722         final MacAddress srcMac = tethered.macAddr;
723         final MacAddress dstMac = tethered.routerMacAddr;
724         final Inet4Address clientIp = tethered.ipv4Addr;
725         final Inet4Address gatewayIp = tethered.ipv4Gatway;
726         final byte[] forwardedQueryPacket = sendUploadPacketDnsV4(srcMac, dstMac, clientIp,
727                 gatewayIp, LOCAL_PORT, DNS_PORT, tester);
728         final ByteBuffer buf = ByteBuffer.wrap(forwardedQueryPacket);
729         Struct.parse(Ipv4Header.class, buf);
730         final UdpHeader udpHeader = Struct.parse(UdpHeader.class, buf);
731         final TestDnsPacket dnsQuery = TestDnsPacket.getTestDnsPacket(buf);
732         assertNotNull(dnsQuery);
733         Log.d(TAG, "Forwarded UDP source port: " + udpHeader.srcPort + ", DNS query id: "
734                 + dnsQuery.getHeader().getId());
735 
736         // [2] Send DNS reply.
737         // DNS server --> upstream --> dnsmasq forwarding --> downstream --> tethered device
738         //
739         // DNS reply transaction id must be copied from DNS query. Used by the requester to match
740         // up replies to outstanding queries. See RFC 1035 section 4.1.1.
741         final Inet4Address remoteIp = (Inet4Address) TEST_IP4_DNS;
742         final Inet4Address tetheringUpstreamIp = (Inet4Address) TEST_IP4_ADDR.getAddress();
743         sendDownloadPacketDnsV4(remoteIp, tetheringUpstreamIp, DNS_PORT,
744                 (short) udpHeader.srcPort, (short) dnsQuery.getHeader().getId(), tester);
745     }
746 
747     @Test
testTetherTcpV4()748     public void testTetherTcpV4() throws Exception {
749         final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
750                 toList(TEST_IP4_DNS));
751         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
752 
753         // TODO: remove the connectivity verification for upstream connected notification race.
754         // See the same reason in runUdp4Test().
755         probeV4TetheringConnectivity(tester, tethered, false /* is4To6 */);
756 
757         runTcpTest(tethered.macAddr /* uploadSrcMac */, tethered.routerMacAddr /* uploadDstMac */,
758                 tethered.ipv4Addr /* uploadSrcIp */, REMOTE_IP4_ADDR /* uploadDstIp */,
759                 REMOTE_IP4_ADDR /* downloadSrcIp */, TEST_IP4_ADDR.getAddress() /* downloadDstIp */,
760                 tester, false /* isClat */);
761     }
762 
763     @Test
testTetherTcpV6()764     public void testTetherTcpV6() throws Exception {
765         final TetheringTester tester = initTetheringTester(toList(TEST_IP6_ADDR),
766                 toList(TEST_IP6_DNS));
767         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, true /* hasIpv6 */);
768 
769         runTcpTest(tethered.macAddr /* uploadSrcMac */, tethered.routerMacAddr /* uploadDstMac */,
770                 tethered.ipv6Addr /* uploadSrcIp */, REMOTE_IP6_ADDR /* uploadDstIp */,
771                 REMOTE_IP6_ADDR /* downloadSrcIp */, tethered.ipv6Addr /* downloadDstIp */,
772                 tester, false /* isClat */);
773     }
774 
775     // TODO: support R device. See b/234727688.
776     @Test
777     @IgnoreUpTo(Build.VERSION_CODES.R)
testTetherClatTcp()778     public void testTetherClatTcp() throws Exception {
779         // CLAT only starts on IPv6 only network.
780         final TetheringTester tester = initTetheringTester(toList(TEST_IP6_ADDR),
781                 toList(TEST_IP6_DNS));
782         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, true /* hasIpv6 */);
783 
784         // Get CLAT IPv6 address.
785         final Inet6Address clatIp6 = getClatIpv6Address(tester, tethered);
786 
787         runTcpTest(tethered.macAddr /* uploadSrcMac */, tethered.routerMacAddr /* uploadDstMac */,
788                 tethered.ipv4Addr /* uploadSrcIp */, REMOTE_IP4_ADDR /* uploadDstIp */,
789                 REMOTE_NAT64_ADDR /* downloadSrcIp */, clatIp6 /* downloadDstIp */,
790                 tester, true /* isClat */);
791     }
792 
793     private static final byte[] ZeroLengthDhcpPacket = new byte[] {
794             // scapy.Ether(
795             //   dst="ff:ff:ff:ff:ff:ff")
796             // scapy.IP(
797             //   dst="255.255.255.255")
798             // scapy.UDP(sport=68, dport=67)
799             /* Ethernet Header */
800             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
801             (byte) 0xe0, (byte) 0x4f, (byte) 0x43, (byte) 0xe6, (byte) 0xfb, (byte) 0xd2,
802             (byte) 0x08, (byte) 0x00,
803             /* Ip header */
804             (byte) 0x45, (byte) 0x00, (byte) 0x00, (byte) 0x1c, (byte) 0x00, (byte) 0x01,
805             (byte) 0x00, (byte) 0x00, (byte) 0x40, (byte) 0x11, (byte) 0xb6, (byte) 0x58,
806             (byte) 0x64, (byte) 0x4f, (byte) 0x60, (byte) 0x29, (byte) 0xff, (byte) 0xff,
807             (byte) 0xff, (byte) 0xff,
808             /* UDP header */
809             (byte) 0x00, (byte) 0x44, (byte) 0x00, (byte) 0x43,
810             (byte) 0x00, (byte) 0x08, (byte) 0x3a, (byte) 0xdf
811     };
812 
813     // This test requires the update in NetworkStackModule(See b/269692093).
814     @NetworkStackModuleTest
815     @Test
testTetherZeroLengthDhcpPacket()816     public void testTetherZeroLengthDhcpPacket() throws Exception {
817         final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
818                 toList(TEST_IP4_DNS));
819         tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
820 
821         // Send a zero-length DHCP packet to upstream DHCP server.
822         final ByteBuffer packet = ByteBuffer.wrap(ZeroLengthDhcpPacket);
823         tester.sendUploadPacket(packet);
824 
825         // Send DHCPDISCOVER packet from another downstream tethered device to verify that
826         // upstream DHCP server doesn't close the listening socket and stop reading, then we
827         // can still receive the next DHCP packet from server.
828         final MacAddress macAddress = MacAddress.fromString("11:22:33:44:55:66");
829         assertTrue(tester.testDhcpServerAlive(macAddress));
830     }
831 }
832