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