1 /* 2 * Copyright (C) 2019 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 package android.net.util; 17 18 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL; 19 import static android.net.TetheringManager.TETHERING_USB; 20 import static android.net.TetheringManager.TETHERING_WIFI; 21 import static android.system.OsConstants.AF_UNIX; 22 import static android.system.OsConstants.EAGAIN; 23 import static android.system.OsConstants.SOCK_CLOEXEC; 24 import static android.system.OsConstants.SOCK_DGRAM; 25 import static android.system.OsConstants.SOCK_NONBLOCK; 26 27 import static junit.framework.Assert.assertEquals; 28 import static junit.framework.Assert.assertFalse; 29 import static junit.framework.Assert.assertTrue; 30 31 import android.net.LinkAddress; 32 import android.net.MacAddress; 33 import android.net.TetheringRequestParcel; 34 import android.system.ErrnoException; 35 import android.system.Os; 36 37 import androidx.test.filters.SmallTest; 38 import androidx.test.runner.AndroidJUnit4; 39 40 import com.android.net.module.util.Ipv6Utils; 41 import com.android.net.module.util.NetworkStackConstants; 42 import com.android.net.module.util.Struct; 43 import com.android.net.module.util.structs.EthernetHeader; 44 import com.android.net.module.util.structs.Icmpv6Header; 45 import com.android.net.module.util.structs.Ipv6Header; 46 import com.android.testutils.MiscAsserts; 47 48 import org.junit.Before; 49 import org.junit.Test; 50 import org.junit.runner.RunWith; 51 52 import java.io.FileDescriptor; 53 import java.net.Inet6Address; 54 import java.net.InetAddress; 55 import java.nio.ByteBuffer; 56 57 @RunWith(AndroidJUnit4.class) 58 @SmallTest 59 public class TetheringUtilsTest { 60 private static final LinkAddress TEST_SERVER_ADDR = new LinkAddress("192.168.43.1/24"); 61 private static final LinkAddress TEST_CLIENT_ADDR = new LinkAddress("192.168.43.5/24"); 62 private static final int PACKET_SIZE = 1500; 63 64 private TetheringRequestParcel mTetheringRequest; 65 66 @Before setUp()67 public void setUp() { 68 mTetheringRequest = makeTetheringRequestParcel(); 69 } 70 makeTetheringRequestParcel()71 public TetheringRequestParcel makeTetheringRequestParcel() { 72 final TetheringRequestParcel request = new TetheringRequestParcel(); 73 request.tetheringType = TETHERING_WIFI; 74 request.localIPv4Address = TEST_SERVER_ADDR; 75 request.staticClientAddress = TEST_CLIENT_ADDR; 76 request.exemptFromEntitlementCheck = false; 77 request.showProvisioningUi = true; 78 return request; 79 } 80 81 @Test testIsTetheringRequestEquals()82 public void testIsTetheringRequestEquals() { 83 TetheringRequestParcel request = makeTetheringRequestParcel(); 84 85 assertTrue(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, mTetheringRequest)); 86 assertTrue(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request)); 87 assertTrue(TetheringUtils.isTetheringRequestEquals(null, null)); 88 assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, null)); 89 assertFalse(TetheringUtils.isTetheringRequestEquals(null, mTetheringRequest)); 90 91 request = makeTetheringRequestParcel(); 92 request.tetheringType = TETHERING_USB; 93 assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request)); 94 95 request = makeTetheringRequestParcel(); 96 request.localIPv4Address = null; 97 request.staticClientAddress = null; 98 assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request)); 99 100 request = makeTetheringRequestParcel(); 101 request.exemptFromEntitlementCheck = true; 102 assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request)); 103 104 request = makeTetheringRequestParcel(); 105 request.showProvisioningUi = false; 106 assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request)); 107 108 request = makeTetheringRequestParcel(); 109 request.connectivityScope = CONNECTIVITY_SCOPE_LOCAL; 110 assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request)); 111 112 MiscAsserts.assertFieldCountEquals(6, TetheringRequestParcel.class); 113 } 114 115 // Writes the specified packet to a filedescriptor, skipping the Ethernet header. 116 // Needed because the Ipv6Utils methods for building packets always include the Ethernet header, 117 // but socket filters applied by TetheringUtils expect the packet to start from the IP header. writePacket(FileDescriptor fd, ByteBuffer pkt)118 private int writePacket(FileDescriptor fd, ByteBuffer pkt) throws Exception { 119 pkt.flip(); 120 int offset = Struct.getSize(EthernetHeader.class); 121 int len = pkt.capacity() - offset; 122 return Os.write(fd, pkt.array(), offset, len); 123 } 124 125 // Reads a packet from the filedescriptor. readIpPacket(FileDescriptor fd)126 private ByteBuffer readIpPacket(FileDescriptor fd) throws Exception { 127 ByteBuffer buf = ByteBuffer.allocate(PACKET_SIZE); 128 Os.read(fd, buf); 129 return buf; 130 } 131 132 private interface SocketFilter { apply(FileDescriptor fd)133 void apply(FileDescriptor fd) throws Exception; 134 } 135 checkIcmpSocketFilter(ByteBuffer passed, ByteBuffer dropped, SocketFilter filter)136 private ByteBuffer checkIcmpSocketFilter(ByteBuffer passed, ByteBuffer dropped, 137 SocketFilter filter) throws Exception { 138 FileDescriptor in = new FileDescriptor(); 139 FileDescriptor out = new FileDescriptor(); 140 Os.socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, in, out); 141 142 // Before the filter is applied, it doesn't drop anything. 143 int len = writePacket(out, dropped); 144 ByteBuffer received = readIpPacket(in); 145 assertEquals(len, received.position()); 146 147 // Install the socket filter. Then write two packets, the first expected to be dropped and 148 // the second expected to be passed. Check that only the second makes it through. 149 filter.apply(in); 150 writePacket(out, dropped); 151 len = writePacket(out, passed); 152 received = readIpPacket(in); 153 assertEquals(len, received.position()); 154 received.flip(); 155 156 // Check there are no more packets to read. 157 try { 158 readIpPacket(in); 159 } catch (ErrnoException expected) { 160 assertEquals(EAGAIN, expected.errno); 161 } 162 163 return received; 164 } 165 166 @Test testIcmpSocketFilters()167 public void testIcmpSocketFilters() throws Exception { 168 MacAddress mac1 = MacAddress.fromString("11:22:33:44:55:66"); 169 MacAddress mac2 = MacAddress.fromString("aa:bb:cc:dd:ee:ff"); 170 Inet6Address ll1 = (Inet6Address) InetAddress.getByName("fe80::1"); 171 Inet6Address ll2 = (Inet6Address) InetAddress.getByName("fe80::abcd"); 172 Inet6Address allRouters = NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST; 173 174 final ByteBuffer na = Ipv6Utils.buildNaPacket(mac1, mac2, ll1, ll2, 0, ll1); 175 final ByteBuffer ns = Ipv6Utils.buildNsPacket(mac1, mac2, ll1, ll2, ll1); 176 final ByteBuffer rs = Ipv6Utils.buildRsPacket(mac1, mac2, ll1, allRouters); 177 178 ByteBuffer received = checkIcmpSocketFilter(na /* passed */, rs /* dropped */, 179 TetheringUtils::setupNaSocket); 180 181 Struct.parse(Ipv6Header.class, received); // Skip IPv6 header. 182 Icmpv6Header icmpv6 = Struct.parse(Icmpv6Header.class, received); 183 assertEquals(NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT, icmpv6.type); 184 185 received = checkIcmpSocketFilter(ns /* passed */, rs /* dropped */, 186 TetheringUtils::setupNsSocket); 187 188 Struct.parse(Ipv6Header.class, received); // Skip IPv6 header. 189 icmpv6 = Struct.parse(Icmpv6Header.class, received); 190 assertEquals(NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION, icmpv6.type); 191 } 192 } 193