1 /*
2  * Copyright (C) 2015 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 org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertTrue;
22 
23 import android.net.netlink.NetlinkConstants;
24 import android.net.netlink.NetlinkMessage;
25 import android.net.netlink.RtNetlinkNeighborMessage;
26 import android.net.netlink.StructNdMsg;
27 import android.net.netlink.StructNlMsgHdr;
28 import android.system.OsConstants;
29 
30 import androidx.test.filters.SmallTest;
31 import androidx.test.runner.AndroidJUnit4;
32 
33 import libcore.util.HexEncoding;
34 
35 import org.junit.Test;
36 import org.junit.runner.RunWith;
37 
38 import java.net.Inet4Address;
39 import java.net.InetAddress;
40 import java.nio.ByteBuffer;
41 import java.nio.ByteOrder;
42 import java.util.Arrays;
43 
44 @RunWith(AndroidJUnit4.class)
45 @SmallTest
46 public class RtNetlinkNeighborMessageTest {
47     private final String TAG = "RtNetlinkNeighborMessageTest";
48 
49     // Hexadecimal representation of packet capture.
50     public static final String RTM_DELNEIGH_HEX =
51             // struct nlmsghdr
52             "4c000000" +     // length = 76
53             "1d00" +         // type = 29 (RTM_DELNEIGH)
54             "0000" +         // flags
55             "00000000" +     // seqno
56             "00000000" +     // pid (0 == kernel)
57             // struct ndmsg
58             "02" +           // family
59             "00" +           // pad1
60             "0000" +         // pad2
61             "15000000" +     // interface index (21  == wlan0, on test device)
62             "0400" +         // NUD state (0x04 == NUD_STALE)
63             "00" +           // flags
64             "01" +           // type
65             // struct nlattr: NDA_DST
66             "0800" +         // length = 8
67             "0100" +         // type (1 == NDA_DST, for neighbor messages)
68             "c0a89ffe" +     // IPv4 address (== 192.168.159.254)
69             // struct nlattr: NDA_LLADDR
70             "0a00" +         // length = 10
71             "0200" +         // type (2 == NDA_LLADDR, for neighbor messages)
72             "00005e000164" + // MAC Address (== 00:00:5e:00:01:64)
73             "0000" +         // padding, for 4 byte alignment
74             // struct nlattr: NDA_PROBES
75             "0800" +         // length = 8
76             "0400" +         // type (4 == NDA_PROBES, for neighbor messages)
77             "01000000" +     // number of probes
78             // struct nlattr: NDA_CACHEINFO
79             "1400" +         // length = 20
80             "0300" +         // type (3 == NDA_CACHEINFO, for neighbor messages)
81             "05190000" +     // ndm_used, as "clock ticks ago"
82             "05190000" +     // ndm_confirmed, as "clock ticks ago"
83             "190d0000" +     // ndm_updated, as "clock ticks ago"
84             "00000000";      // ndm_refcnt
85     public static final byte[] RTM_DELNEIGH =
86             HexEncoding.decode(RTM_DELNEIGH_HEX.toCharArray(), false);
87 
88     // Hexadecimal representation of packet capture.
89     public static final String RTM_NEWNEIGH_HEX =
90             // struct nlmsghdr
91             "58000000" +     // length = 88
92             "1c00" +         // type = 28 (RTM_NEWNEIGH)
93             "0000" +         // flags
94             "00000000" +     // seqno
95             "00000000" +     // pid (0 == kernel)
96             // struct ndmsg
97             "0a" +           // family
98             "00" +           // pad1
99             "0000" +         // pad2
100             "15000000" +     // interface index (21  == wlan0, on test device)
101             "0400" +         // NUD state (0x04 == NUD_STALE)
102             "80" +           // flags
103             "01" +           // type
104             // struct nlattr: NDA_DST
105             "1400" +         // length = 20
106             "0100" +         // type (1 == NDA_DST, for neighbor messages)
107             "fe8000000000000086c9b2fffe6aed4b" + // IPv6 address (== fe80::86c9:b2ff:fe6a:ed4b)
108             // struct nlattr: NDA_LLADDR
109             "0a00" +         // length = 10
110             "0200" +         // type (2 == NDA_LLADDR, for neighbor messages)
111             "84c9b26aed4b" + // MAC Address (== 84:c9:b2:6a:ed:4b)
112             "0000" +         // padding, for 4 byte alignment
113             // struct nlattr: NDA_PROBES
114             "0800" +         // length = 8
115             "0400" +         // type (4 == NDA_PROBES, for neighbor messages)
116             "01000000" +     // number of probes
117             // struct nlattr: NDA_CACHEINFO
118             "1400" +         // length = 20
119             "0300" +         // type (3 == NDA_CACHEINFO, for neighbor messages)
120             "eb0e0000" +     // ndm_used, as "clock ticks ago"
121             "861f0000" +     // ndm_confirmed, as "clock ticks ago"
122             "00000000" +     // ndm_updated, as "clock ticks ago"
123             "05000000";      // ndm_refcnt
124     public static final byte[] RTM_NEWNEIGH =
125             HexEncoding.decode(RTM_NEWNEIGH_HEX.toCharArray(), false);
126 
127     // An example of the full response from an RTM_GETNEIGH query.
128     private static final String RTM_GETNEIGH_RESPONSE_HEX =
129             // <-- struct nlmsghr             -->|<-- struct ndmsg           -->|<-- struct nlattr: NDA_DST             -->|<-- NDA_LLADDR          -->|<-- NDA_PROBES -->|<-- NDA_CACHEINFO                         -->|
130             "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000001 0a00 0200 333300000001 0000 0800 0400 00000000 1400 0300 a2280000 32110000 32110000 01000000" +
131             "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff000001 0a00 0200 3333ff000001 0000 0800 0400 00000000 1400 0300 0d280000 9d100000 9d100000 00000000" +
132             "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 0400 80 01 1400 0100 20010db800040ca00000000000000001 0a00 0200 84c9b26aed4b 0000 0800 0400 04000000 1400 0300 90100000 90100000 90080000 01000000" +
133             "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff47da19 0a00 0200 3333ff47da19 0000 0800 0400 00000000 1400 0300 a1280000 31110000 31110000 01000000" +
134             "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff020000000000000000000000000016 0a00 0200 333300000016 0000 0800 0400 00000000 1400 0300 912a0000 21130000 21130000 00000000" +
135             "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff0200000000000000000001ffeace3b 0a00 0200 3333ffeace3b 0000 0800 0400 00000000 1400 0300 922a0000 22130000 22130000 00000000" +
136             "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff5c2a83 0a00 0200 3333ff5c2a83 0000 0800 0400 00000000 1400 0300 391c0000 c9040000 c9040000 01000000" +
137             "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 01000000 4000 00 02 1400 0100 00000000000000000000000000000000 0a00 0200 000000000000 0000 0800 0400 00000000 1400 0300 cd180200 5d010200 5d010200 08000000" +
138             "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000002 0a00 0200 333300000002 0000 0800 0400 00000000 1400 0300 352a0000 c5120000 c5120000 00000000" +
139             "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000016 0a00 0200 333300000016 0000 0800 0400 00000000 1400 0300 982a0000 28130000 28130000 00000000" +
140             "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 0800 80 01 1400 0100 fe8000000000000086c9b2fffe6aed4b 0a00 0200 84c9b26aed4b 0000 0800 0400 00000000 1400 0300 23000000 24000000 57000000 13000000" +
141             "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ffeace3b 0a00 0200 3333ffeace3b 0000 0800 0400 00000000 1400 0300 992a0000 29130000 29130000 01000000" +
142             "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff020000000000000000000000000002 0a00 0200 333300000002 0000 0800 0400 00000000 1400 0300 2e2a0000 be120000 be120000 00000000" +
143             "44000000 1c00 0200 00000000 3e2b0000 02 00 0000 18000000 4000 00 03 0800 0100 00000000                         0400 0200                   0800 0400 00000000 1400 0300 75280000 05110000 05110000 22000000";
144     public static final byte[] RTM_GETNEIGH_RESPONSE =
145             HexEncoding.decode(RTM_GETNEIGH_RESPONSE_HEX.replaceAll(" ", "").toCharArray(), false);
146 
147     @Test
testParseRtmDelNeigh()148     public void testParseRtmDelNeigh() {
149         final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_DELNEIGH);
150         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
151         final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
152         assertNotNull(msg);
153         assertTrue(msg instanceof RtNetlinkNeighborMessage);
154         final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
155 
156         final StructNlMsgHdr hdr = neighMsg.getHeader();
157         assertNotNull(hdr);
158         assertEquals(76, hdr.nlmsg_len);
159         assertEquals(NetlinkConstants.RTM_DELNEIGH, hdr.nlmsg_type);
160         assertEquals(0, hdr.nlmsg_flags);
161         assertEquals(0, hdr.nlmsg_seq);
162         assertEquals(0, hdr.nlmsg_pid);
163 
164         final StructNdMsg ndmsgHdr = neighMsg.getNdHeader();
165         assertNotNull(ndmsgHdr);
166         assertEquals((byte) OsConstants.AF_INET, ndmsgHdr.ndm_family);
167         assertEquals(21, ndmsgHdr.ndm_ifindex);
168         assertEquals(StructNdMsg.NUD_STALE, ndmsgHdr.ndm_state);
169         final InetAddress destination = neighMsg.getDestination();
170         assertNotNull(destination);
171         assertEquals(InetAddress.parseNumericAddress("192.168.159.254"), destination);
172     }
173 
174     @Test
testParseRtmNewNeigh()175     public void testParseRtmNewNeigh() {
176         final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_NEWNEIGH);
177         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
178         final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
179         assertNotNull(msg);
180         assertTrue(msg instanceof RtNetlinkNeighborMessage);
181         final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
182 
183         final StructNlMsgHdr hdr = neighMsg.getHeader();
184         assertNotNull(hdr);
185         assertEquals(88, hdr.nlmsg_len);
186         assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type);
187         assertEquals(0, hdr.nlmsg_flags);
188         assertEquals(0, hdr.nlmsg_seq);
189         assertEquals(0, hdr.nlmsg_pid);
190 
191         final StructNdMsg ndmsgHdr = neighMsg.getNdHeader();
192         assertNotNull(ndmsgHdr);
193         assertEquals((byte) OsConstants.AF_INET6, ndmsgHdr.ndm_family);
194         assertEquals(21, ndmsgHdr.ndm_ifindex);
195         assertEquals(StructNdMsg.NUD_STALE, ndmsgHdr.ndm_state);
196         final InetAddress destination = neighMsg.getDestination();
197         assertNotNull(destination);
198         assertEquals(InetAddress.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), destination);
199     }
200 
201     @Test
testParseRtmGetNeighResponse()202     public void testParseRtmGetNeighResponse() {
203         final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_GETNEIGH_RESPONSE);
204         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
205 
206         int messageCount = 0;
207         while (byteBuffer.remaining() > 0) {
208             final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
209             assertNotNull(msg);
210             assertTrue(msg instanceof RtNetlinkNeighborMessage);
211             final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
212 
213             final StructNlMsgHdr hdr = neighMsg.getHeader();
214             assertNotNull(hdr);
215             assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type);
216             assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags);
217             assertEquals(0, hdr.nlmsg_seq);
218             assertEquals(11070, hdr.nlmsg_pid);
219 
220             messageCount++;
221         }
222         // TODO: add more detailed spot checks.
223         assertEquals(14, messageCount);
224     }
225 
226     @Test
testCreateRtmNewNeighMessage()227     public void testCreateRtmNewNeighMessage() {
228         final int seqNo = 2635;
229         final int ifIndex = 14;
230         final byte[] llAddr =
231                 new byte[] { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6 };
232 
233         // Hexadecimal representation of our created packet.
234         final String expectedNewNeighHex =
235                 // struct nlmsghdr
236                 "30000000" +     // length = 48
237                 "1c00" +         // type = 28 (RTM_NEWNEIGH)
238                 "0501" +         // flags (NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE)
239                 "4b0a0000" +     // seqno
240                 "00000000" +     // pid (0 == kernel)
241                 // struct ndmsg
242                 "02" +           // family
243                 "00" +           // pad1
244                 "0000" +         // pad2
245                 "0e000000" +     // interface index (14)
246                 "0800" +         // NUD state (0x08 == NUD_DELAY)
247                 "00" +           // flags
248                 "00" +           // type
249                 // struct nlattr: NDA_DST
250                 "0800" +         // length = 8
251                 "0100" +         // type (1 == NDA_DST, for neighbor messages)
252                 "7f000001" +     // IPv4 address (== 127.0.0.1)
253                 // struct nlattr: NDA_LLADDR
254                 "0a00" +         // length = 10
255                 "0200" +         // type (2 == NDA_LLADDR, for neighbor messages)
256                 "010203040506" + // MAC Address (== 01:02:03:04:05:06)
257                 "0000";          // padding, for 4 byte alignment
258         final byte[] expectedNewNeigh =
259                 HexEncoding.decode(expectedNewNeighHex.toCharArray(), false);
260 
261         final byte[] bytes = RtNetlinkNeighborMessage.newNewNeighborMessage(
262             seqNo, Inet4Address.LOOPBACK, StructNdMsg.NUD_DELAY, ifIndex, llAddr);
263         if (!Arrays.equals(expectedNewNeigh, bytes)) {
264             assertEquals(expectedNewNeigh.length, bytes.length);
265             for (int i = 0; i < Math.min(expectedNewNeigh.length, bytes.length); i++) {
266                 assertEquals(expectedNewNeigh[i], bytes[i]);
267             }
268         }
269     }
270 }
271