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 com.android.testutils.ParcelUtils.assertParcelingIsLossless;
20 
21 import static org.junit.Assert.assertArrayEquals;
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
25 
26 import android.net.util.KeepalivePacketDataUtil;
27 import android.os.Build;
28 import android.util.Log;
29 
30 import com.android.testutils.DevSdkIgnoreRule;
31 import com.android.testutils.DevSdkIgnoreRunner;
32 
33 import org.junit.After;
34 import org.junit.Before;
35 import org.junit.Test;
36 import org.junit.runner.RunWith;
37 
38 import java.net.InetAddress;
39 import java.nio.ByteBuffer;
40 
41 @RunWith(DevSdkIgnoreRunner.class)
42 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
43 public final class KeepalivePacketDataUtilTest {
44     private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 1};
45     private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 5};
46 
47     private Log.TerribleFailureHandler mOriginalHandler;
48 
49     @Before
setUp()50     public void setUp() {
51         // Terrible failures are logged when using deprecated methods on newer platforms
52         mOriginalHandler = Log.setWtfHandler((tag, what, sys) ->
53                 Log.e(tag, "Terrible failure in test", what));
54     }
55 
56     @After
tearDown()57     public void tearDown() {
58         Log.setWtfHandler(mOriginalHandler);
59     }
60 
61     @Test
testFromTcpKeepaliveStableParcelable()62     public void testFromTcpKeepaliveStableParcelable() throws Exception {
63         final int srcPort = 1234;
64         final int dstPort = 4321;
65         final int seq = 0x11111111;
66         final int ack = 0x22222222;
67         final int wnd = 8000;
68         final int wndScale = 2;
69         final int tos = 4;
70         final int ttl = 64;
71         TcpKeepalivePacketData resultData = null;
72         final TcpKeepalivePacketDataParcelable testInfo = new TcpKeepalivePacketDataParcelable();
73         testInfo.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
74         testInfo.srcPort = srcPort;
75         testInfo.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
76         testInfo.dstPort = dstPort;
77         testInfo.seq = seq;
78         testInfo.ack = ack;
79         testInfo.rcvWnd = wnd;
80         testInfo.rcvWndScale = wndScale;
81         testInfo.tos = tos;
82         testInfo.ttl = ttl;
83         try {
84             resultData = KeepalivePacketDataUtil.fromStableParcelable(testInfo);
85         } catch (InvalidPacketException e) {
86             fail("InvalidPacketException: " + e);
87         }
88 
89         assertEquals(InetAddress.getByAddress(testInfo.srcAddress), resultData.getSrcAddress());
90         assertEquals(InetAddress.getByAddress(testInfo.dstAddress), resultData.getDstAddress());
91         assertEquals(testInfo.srcPort, resultData.getSrcPort());
92         assertEquals(testInfo.dstPort, resultData.getDstPort());
93         assertEquals(testInfo.seq, resultData.tcpSeq);
94         assertEquals(testInfo.ack, resultData.tcpAck);
95         assertEquals(testInfo.rcvWnd, resultData.tcpWindow);
96         assertEquals(testInfo.rcvWndScale, resultData.tcpWindowScale);
97         assertEquals(testInfo.tos, resultData.ipTos);
98         assertEquals(testInfo.ttl, resultData.ipTtl);
99 
100         assertParcelingIsLossless(resultData);
101 
102         final byte[] packet = resultData.getPacket();
103         // IP version and IHL
104         assertEquals(packet[0], 0x45);
105         // TOS
106         assertEquals(packet[1], tos);
107         // TTL
108         assertEquals(packet[8], ttl);
109         // Source IP address.
110         byte[] ip = new byte[4];
111         ByteBuffer buf = ByteBuffer.wrap(packet, 12, 4);
112         buf.get(ip);
113         assertArrayEquals(ip, IPV4_KEEPALIVE_SRC_ADDR);
114         // Destination IP address.
115         buf = ByteBuffer.wrap(packet, 16, 4);
116         buf.get(ip);
117         assertArrayEquals(ip, IPV4_KEEPALIVE_DST_ADDR);
118 
119         buf = ByteBuffer.wrap(packet, 20, 12);
120         // Source port.
121         assertEquals(buf.getShort(), srcPort);
122         // Destination port.
123         assertEquals(buf.getShort(), dstPort);
124         // Sequence number.
125         assertEquals(buf.getInt(), seq);
126         // Ack.
127         assertEquals(buf.getInt(), ack);
128         // Window size.
129         buf = ByteBuffer.wrap(packet, 34, 2);
130         assertEquals(buf.getShort(), wnd >> wndScale);
131     }
132 
133     //TODO: add ipv6 test when ipv6 supported
134 
135     @Test
testToTcpKeepaliveStableParcelable()136     public void testToTcpKeepaliveStableParcelable() throws Exception {
137         final int srcPort = 1234;
138         final int dstPort = 4321;
139         final int sequence = 0x11111111;
140         final int ack = 0x22222222;
141         final int wnd = 48_000;
142         final int wndScale = 2;
143         final int tos = 4;
144         final int ttl = 64;
145         final TcpKeepalivePacketDataParcelable testInfo = new TcpKeepalivePacketDataParcelable();
146         testInfo.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
147         testInfo.srcPort = srcPort;
148         testInfo.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
149         testInfo.dstPort = dstPort;
150         testInfo.seq = sequence;
151         testInfo.ack = ack;
152         testInfo.rcvWnd = wnd;
153         testInfo.rcvWndScale = wndScale;
154         testInfo.tos = tos;
155         testInfo.ttl = ttl;
156         TcpKeepalivePacketData testData = null;
157         TcpKeepalivePacketDataParcelable resultData = null;
158         testData = KeepalivePacketDataUtil.fromStableParcelable(testInfo);
159         resultData = KeepalivePacketDataUtil.toStableParcelable(testData);
160         assertArrayEquals(resultData.srcAddress, IPV4_KEEPALIVE_SRC_ADDR);
161         assertArrayEquals(resultData.dstAddress, IPV4_KEEPALIVE_DST_ADDR);
162         assertEquals(resultData.srcPort, srcPort);
163         assertEquals(resultData.dstPort, dstPort);
164         assertEquals(resultData.seq, sequence);
165         assertEquals(resultData.ack, ack);
166         assertEquals(resultData.rcvWnd, wnd);
167         assertEquals(resultData.rcvWndScale, wndScale);
168         assertEquals(resultData.tos, tos);
169         assertEquals(resultData.ttl, ttl);
170 
171         final String expected = ""
172                 + "android.net.TcpKeepalivePacketDataParcelable{srcAddress: [10, 0, 0, 1],"
173                 + " srcPort: 1234, dstAddress: [10, 0, 0, 5], dstPort: 4321, seq: 286331153,"
174                 + " ack: 572662306, rcvWnd: 48000, rcvWndScale: 2, tos: 4, ttl: 64}";
175         assertEquals(expected, resultData.toString());
176     }
177 
178     @Test
testParseTcpKeepalivePacketData()179     public void testParseTcpKeepalivePacketData() throws Exception {
180         final int srcPort = 1234;
181         final int dstPort = 4321;
182         final int sequence = 0x11111111;
183         final int ack = 0x22222222;
184         final int wnd = 4800;
185         final int wndScale = 2;
186         final int tos = 4;
187         final int ttl = 64;
188         final TcpKeepalivePacketDataParcelable testParcel = new TcpKeepalivePacketDataParcelable();
189         testParcel.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
190         testParcel.srcPort = srcPort;
191         testParcel.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
192         testParcel.dstPort = dstPort;
193         testParcel.seq = sequence;
194         testParcel.ack = ack;
195         testParcel.rcvWnd = wnd;
196         testParcel.rcvWndScale = wndScale;
197         testParcel.tos = tos;
198         testParcel.ttl = ttl;
199 
200         final KeepalivePacketData testData =
201                 KeepalivePacketDataUtil.fromStableParcelable(testParcel);
202         final TcpKeepalivePacketDataParcelable parsedParcelable =
203                 KeepalivePacketDataUtil.parseTcpKeepalivePacketData(testData);
204         final TcpKeepalivePacketData roundTripData =
205                 KeepalivePacketDataUtil.fromStableParcelable(parsedParcelable);
206 
207         // Generated packet is the same, but rcvWnd / wndScale will differ if scale is non-zero
208         assertTrue(testData.getPacket().length > 0);
209         assertArrayEquals(testData.getPacket(), roundTripData.getPacket());
210 
211         testParcel.rcvWndScale = 0;
212         final KeepalivePacketData noScaleTestData =
213                 KeepalivePacketDataUtil.fromStableParcelable(testParcel);
214         final TcpKeepalivePacketDataParcelable noScaleParsedParcelable =
215                 KeepalivePacketDataUtil.parseTcpKeepalivePacketData(noScaleTestData);
216         final TcpKeepalivePacketData noScaleRoundTripData =
217                 KeepalivePacketDataUtil.fromStableParcelable(noScaleParsedParcelable);
218         assertEquals(noScaleTestData, noScaleRoundTripData);
219         assertTrue(noScaleTestData.getPacket().length > 0);
220         assertArrayEquals(noScaleTestData.getPacket(), noScaleRoundTripData.getPacket());
221     }
222 }
223