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