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.netlink;
18 
19 import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
20 import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
21 import static android.system.OsConstants.AF_INET;
22 import static android.system.OsConstants.AF_INET6;
23 import static android.system.OsConstants.IPPROTO_TCP;
24 import static android.system.OsConstants.IPPROTO_UDP;
25 
26 import static org.junit.Assert.assertArrayEquals;
27 import static org.junit.Assert.assertEquals;
28 import static org.junit.Assert.assertNotNull;
29 import static org.junit.Assert.assertTrue;
30 import static org.junit.Assert.fail;
31 
32 import androidx.test.filters.SmallTest;
33 import androidx.test.runner.AndroidJUnit4;
34 
35 import libcore.util.HexEncoding;
36 
37 import org.junit.Test;
38 import org.junit.runner.RunWith;
39 
40 import java.net.InetAddress;
41 import java.net.InetSocketAddress;
42 import java.nio.ByteBuffer;
43 import java.nio.ByteOrder;
44 
45 @RunWith(AndroidJUnit4.class)
46 @SmallTest
47 public class InetDiagSocketTest {
48     // Hexadecimal representation of InetDiagReqV2 request.
49     private static final String INET_DIAG_REQ_V2_UDP_INET4_HEX =
50             // struct nlmsghdr
51             "48000000" +     // length = 72
52             "1400" +         // type = SOCK_DIAG_BY_FAMILY
53             "0103" +         // flags = NLM_F_REQUEST | NLM_F_DUMP
54             "00000000" +     // seqno
55             "00000000" +     // pid (0 == kernel)
56             // struct inet_diag_req_v2
57             "02" +           // family = AF_INET
58             "11" +           // protcol = IPPROTO_UDP
59             "00" +           // idiag_ext
60             "00" +           // pad
61             "ffffffff" +     // idiag_states
62             // inet_diag_sockid
63             "a5de" +         // idiag_sport = 42462
64             "b971" +         // idiag_dport = 47473
65             "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2
66             "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8
67             "00000000" +     // idiag_if
68             "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
69     private static final byte[] INET_DIAG_REQ_V2_UDP_INET4_BYTES =
70             HexEncoding.decode(INET_DIAG_REQ_V2_UDP_INET4_HEX.toCharArray(), false);
71 
72     @Test
testInetDiagReqV2UdpInet4()73     public void testInetDiagReqV2UdpInet4() throws Exception {
74         InetSocketAddress local = new InetSocketAddress(InetAddress.getByName("10.0.100.2"),
75                 42462);
76         InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
77                 47473);
78         final byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_UDP, local, remote, AF_INET,
79                 (short) (NLM_F_REQUEST | NLM_F_DUMP));
80         assertArrayEquals(INET_DIAG_REQ_V2_UDP_INET4_BYTES, msg);
81     }
82 
83     // Hexadecimal representation of InetDiagReqV2 request.
84     private static final String INET_DIAG_REQ_V2_TCP_INET6_HEX =
85             // struct nlmsghdr
86             "48000000" +     // length = 72
87             "1400" +         // type = SOCK_DIAG_BY_FAMILY
88             "0100" +         // flags = NLM_F_REQUEST
89             "00000000" +     // seqno
90             "00000000" +     // pid (0 == kernel)
91             // struct inet_diag_req_v2
92             "0a" +           // family = AF_INET6
93             "06" +           // protcol = IPPROTO_TCP
94             "00" +           // idiag_ext
95             "00" +           // pad
96             "ffffffff" +     // idiag_states
97                 // inet_diag_sockid
98                 "a5de" +         // idiag_sport = 42462
99                 "b971" +         // idiag_dport = 47473
100                 "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b
101                 "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8
102                 "00000000" +     // idiag_if
103                 "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
104     private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_BYTES =
105             HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_HEX.toCharArray(), false);
106 
107     @Test
testInetDiagReqV2TcpInet6()108     public void testInetDiagReqV2TcpInet6() throws Exception {
109         InetSocketAddress local = new InetSocketAddress(
110                 InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462);
111         InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
112                 47473);
113         byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6,
114                 NLM_F_REQUEST);
115 
116         assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg);
117     }
118 
119     // Hexadecimal representation of InetDiagReqV2 request with extension, INET_DIAG_INFO.
120     private static final String INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX =
121             // struct nlmsghdr
122             "48000000" +     // length = 72
123             "1400" +         // type = SOCK_DIAG_BY_FAMILY
124             "0100" +         // flags = NLM_F_REQUEST
125             "00000000" +     // seqno
126             "00000000" +     // pid (0 == kernel)
127             // struct inet_diag_req_v2
128             "02" +           // family = AF_INET
129             "06" +           // protcol = IPPROTO_TCP
130             "02" +           // idiag_ext = INET_DIAG_INFO
131             "00" +           // pad
132             "ffffffff" +   // idiag_states
133             // inet_diag_sockid
134             "3039" +         // idiag_sport = 12345
135             "d431" +         // idiag_dport = 54321
136             "01020304000000000000000000000000" + // idiag_src = 1.2.3.4
137             "08080404000000000000000000000000" + // idiag_dst = 8.8.4.4
138             "00000000" +     // idiag_if
139             "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
140 
141     private static final byte[] INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES =
142             HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX.toCharArray(), false);
143     private static final int TCP_ALL_STATES = 0xffffffff;
144     @Test
testInetDiagReqV2TcpInetWithExt()145     public void testInetDiagReqV2TcpInetWithExt() throws Exception {
146         InetSocketAddress local = new InetSocketAddress(
147                 InetAddress.getByName("1.2.3.4"), 12345);
148         InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"),
149                 54321);
150         byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET,
151                 NLM_F_REQUEST, 0 /* pad */, 2 /* idiagExt */, TCP_ALL_STATES);
152 
153         assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES, msg);
154 
155         local = new InetSocketAddress(
156                 InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462);
157         remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
158                 47473);
159         msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6,
160                 NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
161 
162         assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg);
163     }
164 
165     // Hexadecimal representation of InetDiagReqV2 request with no socket specified.
166     private static final String INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX =
167             // struct nlmsghdr
168             "48000000" +     // length = 72
169             "1400" +         // type = SOCK_DIAG_BY_FAMILY
170             "0100" +         // flags = NLM_F_REQUEST
171             "00000000" +     // seqno
172             "00000000" +     // pid (0 == kernel)
173             // struct inet_diag_req_v2
174             "0a" +           // family = AF_INET6
175             "06" +           // protcol = IPPROTO_TCP
176             "00" +           // idiag_ext
177             "00" +           // pad
178             "ffffffff" +     // idiag_states
179             // inet_diag_sockid
180             "0000" +         // idiag_sport
181             "0000" +         // idiag_dport
182             "00000000000000000000000000000000" + // idiag_src
183             "00000000000000000000000000000000" + // idiag_dst
184             "00000000" +     // idiag_if
185             "0000000000000000"; // idiag_cookie
186 
187     private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES =
188             HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX.toCharArray(), false);
189 
190     @Test
testInetDiagReqV2TcpInet6NoIdSpecified()191     public void testInetDiagReqV2TcpInet6NoIdSpecified() throws Exception {
192         InetSocketAddress local = new InetSocketAddress(
193                 InetAddress.getByName("fe80::fe6a:ed4b"), 12345);
194         InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"),
195                 54321);
196         // Verify no socket specified if either local or remote socket address is null.
197         byte[] msgExt = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6,
198                 NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
199         byte[] msg;
200         try {
201             msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, remote, AF_INET6,
202                     NLM_F_REQUEST);
203             fail("Both remote and local should be null, expected UnknownHostException");
204         } catch (NullPointerException e) {
205         }
206 
207         try {
208             msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, null, AF_INET6,
209                     NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
210             fail("Both remote and local should be null, expected UnknownHostException");
211         } catch (NullPointerException e) {
212         }
213 
214         msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6,
215                 NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
216         assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES, msg);
217         assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES, msgExt);
218     }
219 
220     // Hexadecimal representation of InetDiagReqV2 request.
221     private static final String INET_DIAG_MSG_HEX =
222             // struct nlmsghdr
223             "58000000" +     // length = 88
224             "1400" +         // type = SOCK_DIAG_BY_FAMILY
225             "0200" +         // flags = NLM_F_MULTI
226             "00000000" +     // seqno
227             "f5220000" +     // pid (0 == kernel)
228             // struct inet_diag_msg
229             "0a" +           // family = AF_INET6
230             "01" +           // idiag_state
231             "00" +           // idiag_timer
232             "00" +           // idiag_retrans
233                 // inet_diag_sockid
234                 "a817" +     // idiag_sport = 43031
235                 "960f" +     // idiag_dport = 38415
236                 "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b
237                 "00000000000000000000ffff08080808" + // idiag_dst = 8.8.8.8
238                 "00000000" + // idiag_if
239                 "ffffffffffffffff" + // idiag_cookie = INET_DIAG_NOCOOKIE
240             "00000000" +     // idiag_expires
241             "00000000" +     // idiag_rqueue
242             "00000000" +     // idiag_wqueue
243             "a3270000" +     // idiag_uid
244             "A57E1900";      // idiag_inode
245     private static final byte[] INET_DIAG_MSG_BYTES =
246             HexEncoding.decode(INET_DIAG_MSG_HEX.toCharArray(), false);
247 
248     @Test
testParseInetDiagResponse()249     public void testParseInetDiagResponse() throws Exception {
250         final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_BYTES);
251         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
252         final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
253         assertNotNull(msg);
254 
255         assertTrue(msg instanceof InetDiagMessage);
256         final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg;
257         assertEquals(10147, inetDiagMsg.mStructInetDiagMsg.idiag_uid);
258 
259         final StructNlMsgHdr hdr = inetDiagMsg.getHeader();
260         assertNotNull(hdr);
261         assertEquals(NetlinkConstants.SOCK_DIAG_BY_FAMILY, hdr.nlmsg_type);
262         assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags);
263         assertEquals(0, hdr.nlmsg_seq);
264         assertEquals(8949, hdr.nlmsg_pid);
265     }
266 }
267