| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.net.module.util.netlink; |
| |
| import static android.os.Process.ROOT_UID; |
| import static android.os.Process.SHELL_UID; |
| import static android.system.OsConstants.AF_INET; |
| import static android.system.OsConstants.AF_INET6; |
| import static android.system.OsConstants.IPPROTO_TCP; |
| import static android.system.OsConstants.IPPROTO_UDP; |
| import static android.system.OsConstants.NETLINK_INET_DIAG; |
| |
| import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DESTROY; |
| import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK; |
| import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; |
| import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; |
| |
| import static org.junit.Assert.assertArrayEquals; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import android.net.InetAddresses; |
| import android.util.ArraySet; |
| import android.util.Range; |
| |
| import androidx.test.filters.SmallTest; |
| import androidx.test.runner.AndroidJUnit4; |
| |
| import libcore.util.HexEncoding; |
| |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import java.net.Inet6Address; |
| import java.net.InetAddress; |
| import java.net.InetSocketAddress; |
| import java.net.UnknownHostException; |
| import java.nio.ByteBuffer; |
| import java.nio.ByteOrder; |
| import java.util.List; |
| import java.util.Set; |
| |
| @RunWith(AndroidJUnit4.class) |
| @SmallTest |
| public class InetDiagSocketTest { |
| // ::FFFF:192.0.2.1 |
| private static final byte[] SRC_V4_MAPPED_V6_ADDRESS_BYTES = { |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, |
| (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01, |
| }; |
| // ::FFFF:192.0.2.2 |
| private static final byte[] DST_V4_MAPPED_V6_ADDRESS_BYTES = { |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, |
| (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x02, |
| }; |
| |
| // Hexadecimal representation of InetDiagReqV2 request. |
| private static final String INET_DIAG_REQ_V2_UDP_INET4_HEX = |
| // struct nlmsghdr |
| "48000000" + // length = 72 |
| "1400" + // type = SOCK_DIAG_BY_FAMILY |
| "0103" + // flags = NLM_F_REQUEST | NLM_F_DUMP |
| "00000000" + // seqno |
| "00000000" + // pid (0 == kernel) |
| // struct inet_diag_req_v2 |
| "02" + // family = AF_INET |
| "11" + // protcol = IPPROTO_UDP |
| "00" + // idiag_ext |
| "00" + // pad |
| "ffffffff" + // idiag_states |
| // inet_diag_sockid |
| "a5de" + // idiag_sport = 42462 |
| "b971" + // idiag_dport = 47473 |
| "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2 |
| "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8 |
| "00000000" + // idiag_if |
| "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE |
| private static final byte[] INET_DIAG_REQ_V2_UDP_INET4_BYTES = |
| HexEncoding.decode(INET_DIAG_REQ_V2_UDP_INET4_HEX.toCharArray(), false); |
| |
| @Test |
| public void testInetDiagReqV2UdpInet4() throws Exception { |
| InetSocketAddress local = new InetSocketAddress(InetAddress.getByName("10.0.100.2"), |
| 42462); |
| InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"), |
| 47473); |
| final byte[] msg = InetDiagMessage.inetDiagReqV2(IPPROTO_UDP, local, remote, AF_INET, |
| (short) (NLM_F_REQUEST | NLM_F_DUMP)); |
| assertArrayEquals(INET_DIAG_REQ_V2_UDP_INET4_BYTES, msg); |
| } |
| |
| // Hexadecimal representation of InetDiagReqV2 request. |
| private static final String INET_DIAG_REQ_V2_TCP_INET6_HEX = |
| // struct nlmsghdr |
| "48000000" + // length = 72 |
| "1400" + // type = SOCK_DIAG_BY_FAMILY |
| "0100" + // flags = NLM_F_REQUEST |
| "00000000" + // seqno |
| "00000000" + // pid (0 == kernel) |
| // struct inet_diag_req_v2 |
| "0a" + // family = AF_INET6 |
| "06" + // protcol = IPPROTO_TCP |
| "00" + // idiag_ext |
| "00" + // pad |
| "ffffffff" + // idiag_states |
| // inet_diag_sockid |
| "a5de" + // idiag_sport = 42462 |
| "b971" + // idiag_dport = 47473 |
| "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b |
| "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8 |
| "00000000" + // idiag_if |
| "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE |
| private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_BYTES = |
| HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_HEX.toCharArray(), false); |
| |
| @Test |
| public void testInetDiagReqV2TcpInet6() throws Exception { |
| InetSocketAddress local = new InetSocketAddress( |
| InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462); |
| InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"), |
| 47473); |
| byte[] msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6, |
| NLM_F_REQUEST); |
| |
| assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg); |
| } |
| |
| // Hexadecimal representation of InetDiagReqV2 request with extension, INET_DIAG_INFO. |
| private static final String INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX = |
| // struct nlmsghdr |
| "48000000" + // length = 72 |
| "1400" + // type = SOCK_DIAG_BY_FAMILY |
| "0100" + // flags = NLM_F_REQUEST |
| "00000000" + // seqno |
| "00000000" + // pid (0 == kernel) |
| // struct inet_diag_req_v2 |
| "02" + // family = AF_INET |
| "06" + // protcol = IPPROTO_TCP |
| "02" + // idiag_ext = INET_DIAG_INFO |
| "00" + // pad |
| "ffffffff" + // idiag_states |
| // inet_diag_sockid |
| "3039" + // idiag_sport = 12345 |
| "d431" + // idiag_dport = 54321 |
| "01020304000000000000000000000000" + // idiag_src = 1.2.3.4 |
| "08080404000000000000000000000000" + // idiag_dst = 8.8.4.4 |
| "00000000" + // idiag_if |
| "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE |
| |
| private static final byte[] INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES = |
| HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX.toCharArray(), false); |
| private static final int TCP_ALL_STATES = 0xffffffff; |
| @Test |
| public void testInetDiagReqV2TcpInetWithExt() throws Exception { |
| InetSocketAddress local = new InetSocketAddress( |
| InetAddress.getByName("1.2.3.4"), 12345); |
| InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"), |
| 54321); |
| byte[] msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET, |
| NLM_F_REQUEST, 0 /* pad */, 2 /* idiagExt */, TCP_ALL_STATES); |
| |
| assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES, msg); |
| |
| local = new InetSocketAddress( |
| InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462); |
| remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"), |
| 47473); |
| msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6, |
| NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES); |
| |
| assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg); |
| } |
| |
| // Hexadecimal representation of InetDiagReqV2 request with no socket specified. |
| private static final String INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX = |
| // struct nlmsghdr |
| "48000000" + // length = 72 |
| "1400" + // type = SOCK_DIAG_BY_FAMILY |
| "0100" + // flags = NLM_F_REQUEST |
| "00000000" + // seqno |
| "00000000" + // pid (0 == kernel) |
| // struct inet_diag_req_v2 |
| "0a" + // family = AF_INET6 |
| "06" + // protcol = IPPROTO_TCP |
| "00" + // idiag_ext |
| "00" + // pad |
| "ffffffff" + // idiag_states |
| // inet_diag_sockid |
| "0000" + // idiag_sport |
| "0000" + // idiag_dport |
| "00000000000000000000000000000000" + // idiag_src |
| "00000000000000000000000000000000" + // idiag_dst |
| "00000000" + // idiag_if |
| "0000000000000000"; // idiag_cookie |
| |
| private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_BYTES = |
| HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX.toCharArray(), false); |
| |
| @Test |
| public void testInetDiagReqV2TcpInet6NoIdSpecified() throws Exception { |
| InetSocketAddress local = new InetSocketAddress( |
| InetAddress.getByName("fe80::fe6a:ed4b"), 12345); |
| InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"), |
| 54321); |
| // Verify no socket specified if either local or remote socket address is null. |
| byte[] msgExt = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6, |
| NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES); |
| byte[] msg; |
| try { |
| msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, null, remote, AF_INET6, |
| NLM_F_REQUEST); |
| fail("Both remote and local should be null, expected UnknownHostException"); |
| } catch (IllegalArgumentException e) { |
| } |
| |
| try { |
| msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, local, null, AF_INET6, |
| NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES); |
| fail("Both remote and local should be null, expected UnknownHostException"); |
| } catch (IllegalArgumentException e) { |
| } |
| |
| msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6, |
| NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES); |
| assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_BYTES, msg); |
| assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_BYTES, msgExt); |
| } |
| |
| // Hexadecimal representation of InetDiagReqV2 request with v4-mapped v6 address |
| private static final String INET_DIAG_REQ_V2_TCP_INET6_V4_MAPPED_HEX = |
| // struct nlmsghdr |
| "48000000" + // length = 72 |
| "1400" + // type = SOCK_DIAG_BY_FAMILY |
| "0100" + // flags = NLM_F_REQUEST |
| "00000000" + // seqno |
| "00000000" + // pid (0 == kernel) |
| // struct inet_diag_req_v2 |
| "0a" + // family = AF_INET6 |
| "06" + // protcol = IPPROTO_TCP |
| "00" + // idiag_ext |
| "00" + // pad |
| "ffffffff" + // idiag_states |
| // inet_diag_sockid |
| "a817" + // idiag_sport = 43031 |
| "960f" + // idiag_dport = 38415 |
| "00000000000000000000ffffc0000201" + // idiag_src = ::FFFF:192.0.2.1 |
| "00000000000000000000ffffc0000202" + // idiag_dst = ::FFFF:192.0.2.2 |
| "00000000" + // idiag_if |
| "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE |
| |
| private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_V4_MAPPED_BYTES = |
| HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_V4_MAPPED_HEX.toCharArray(), false); |
| |
| @Test |
| public void testInetDiagReqV2TcpInet6V4Mapped() throws Exception { |
| final Inet6Address srcAddr = Inet6Address.getByAddress( |
| null /* host */, SRC_V4_MAPPED_V6_ADDRESS_BYTES, -1 /* scope_id */); |
| final Inet6Address dstAddr = Inet6Address.getByAddress( |
| null /* host */, DST_V4_MAPPED_V6_ADDRESS_BYTES, -1 /* scope_id */); |
| final byte[] msg = InetDiagMessage.inetDiagReqV2( |
| IPPROTO_TCP, |
| new InetSocketAddress(srcAddr, 43031), |
| new InetSocketAddress(dstAddr, 38415), |
| AF_INET6, |
| NLM_F_REQUEST); |
| assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_V4_MAPPED_BYTES, msg); |
| } |
| |
| // Hexadecimal representation of InetDiagReqV2 request with SOCK_DESTROY |
| private static final String INET_DIAG_REQ_V2_TCP_INET6_DESTROY_HEX = |
| // struct nlmsghdr |
| "48000000" + // length = 72 |
| "1500" + // type = SOCK_DESTROY |
| "0500" + // flags = NLM_F_REQUEST | NLM_F_ACK |
| "00000000" + // seqno |
| "00000000" + // pid (0 == kernel) |
| // struct inet_diag_req_v2 |
| "0a" + // family = AF_INET6 |
| "06" + // protcol = IPPROTO_TCP |
| "00" + // idiag_ext |
| "00" + // pad |
| "ffffffff" + // idiag_states = TCP_ALL_STATES |
| // inet_diag_sockid |
| "a817" + // idiag_sport = 43031 |
| "960f" + // idiag_dport = 38415 |
| "20010db8000000000000000000000001" + // idiag_src = 2001:db8::1 |
| "20010db8000000000000000000000002" + // idiag_dst = 2001:db8::2 |
| "07000000" + // idiag_if = 7 |
| "5800000000000000"; // idiag_cookie = 88 |
| |
| private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_DESTROY_BYTES = |
| HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_DESTROY_HEX.toCharArray(), false); |
| |
| @Test |
| public void testInetDiagReqV2TcpInet6Destroy() throws Exception { |
| final StructInetDiagSockId sockId = new StructInetDiagSockId( |
| new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::1"), 43031), |
| new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::2"), 38415), |
| 7 /* ifIndex */, |
| 88 /* cookie */); |
| final byte[] msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, sockId, AF_INET6, |
| SOCK_DESTROY, (short) (NLM_F_REQUEST | NLM_F_ACK), 0 /* pad */, 0 /* idiagExt */, |
| TCP_ALL_STATES); |
| |
| assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_DESTROY_BYTES, msg); |
| } |
| |
| private void assertNlMsgHdr(StructNlMsgHdr hdr, short type, short flags, int seq, int pid) { |
| assertNotNull(hdr); |
| assertEquals(type, hdr.nlmsg_type); |
| assertEquals(flags, hdr.nlmsg_flags); |
| assertEquals(seq, hdr.nlmsg_seq); |
| assertEquals(pid, hdr.nlmsg_pid); |
| } |
| |
| private void assertInetDiagSockId(StructInetDiagSockId sockId, |
| InetSocketAddress locSocketAddress, InetSocketAddress remSocketAddress, |
| int ifIndex, long cookie) { |
| assertEquals(locSocketAddress, sockId.locSocketAddress); |
| assertEquals(remSocketAddress, sockId.remSocketAddress); |
| assertEquals(ifIndex, sockId.ifIndex); |
| assertEquals(cookie, sockId.cookie); |
| } |
| |
| // Hexadecimal representation of InetDiagMessage |
| private static final String INET_DIAG_MSG_HEX1 = |
| // struct nlmsghdr |
| "58000000" + // length = 88 |
| "1400" + // type = SOCK_DIAG_BY_FAMILY |
| "0200" + // flags = NLM_F_MULTI |
| "00000000" + // seqno |
| "f5220000" + // pid |
| // struct inet_diag_msg |
| "0a" + // family = AF_INET6 |
| "01" + // idiag_state = 1 |
| "02" + // idiag_timer = 2 |
| "ff" + // idiag_retrans = 255 |
| // inet_diag_sockid |
| "a817" + // idiag_sport = 43031 |
| "960f" + // idiag_dport = 38415 |
| "20010db8000000000000000000000001" + // idiag_src = 2001:db8::1 |
| "20010db8000000000000000000000002" + // idiag_dst = 2001:db8::2 |
| "07000000" + // idiag_if = 7 |
| "5800000000000000" + // idiag_cookie = 88 |
| "04000000" + // idiag_expires = 4 |
| "05000000" + // idiag_rqueue = 5 |
| "06000000" + // idiag_wqueue = 6 |
| "a3270000" + // idiag_uid = 10147 |
| "a57e19f0"; // idiag_inode = 4028202661 |
| |
| private void assertInetDiagMsg1(final NetlinkMessage msg) { |
| assertNotNull(msg); |
| |
| assertTrue(msg instanceof InetDiagMessage); |
| final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg; |
| |
| assertNlMsgHdr(inetDiagMsg.getHeader(), |
| NetlinkConstants.SOCK_DIAG_BY_FAMILY, |
| StructNlMsgHdr.NLM_F_MULTI, |
| 0 /* seq */, |
| 8949 /* pid */); |
| |
| assertEquals(AF_INET6, inetDiagMsg.inetDiagMsg.idiag_family); |
| assertEquals(1, inetDiagMsg.inetDiagMsg.idiag_state); |
| assertEquals(2, inetDiagMsg.inetDiagMsg.idiag_timer); |
| assertEquals(255, inetDiagMsg.inetDiagMsg.idiag_retrans); |
| assertInetDiagSockId(inetDiagMsg.inetDiagMsg.id, |
| new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::1"), 43031), |
| new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::2"), 38415), |
| 7 /* ifIndex */, |
| 88 /* cookie */); |
| assertEquals(4, inetDiagMsg.inetDiagMsg.idiag_expires); |
| assertEquals(5, inetDiagMsg.inetDiagMsg.idiag_rqueue); |
| assertEquals(6, inetDiagMsg.inetDiagMsg.idiag_wqueue); |
| assertEquals(10147, inetDiagMsg.inetDiagMsg.idiag_uid); |
| assertEquals(4028202661L, inetDiagMsg.inetDiagMsg.idiag_inode); |
| } |
| |
| // Hexadecimal representation of InetDiagMessage |
| private static final String INET_DIAG_MSG_HEX2 = |
| // struct nlmsghdr |
| "58000000" + // length = 88 |
| "1400" + // type = SOCK_DIAG_BY_FAMILY |
| "0200" + // flags = NLM_F_MULTI |
| "00000000" + // seqno |
| "f5220000" + // pid |
| // struct inet_diag_msg |
| "0a" + // family = AF_INET6 |
| "02" + // idiag_state = 2 |
| "10" + // idiag_timer = 16 |
| "20" + // idiag_retrans = 32 |
| // inet_diag_sockid |
| "a845" + // idiag_sport = 43077 |
| "01bb" + // idiag_dport = 443 |
| "20010db8000000000000000000000003" + // idiag_src = 2001:db8::3 |
| "20010db8000000000000000000000004" + // idiag_dst = 2001:db8::4 |
| "08000000" + // idiag_if = 8 |
| "6300000000000000" + // idiag_cookie = 99 |
| "30000000" + // idiag_expires = 48 |
| "40000000" + // idiag_rqueue = 64 |
| "50000000" + // idiag_wqueue = 80 |
| "39300000" + // idiag_uid = 12345 |
| "851a0000"; // idiag_inode = 6789 |
| |
| private void assertInetDiagMsg2(final NetlinkMessage msg) { |
| assertNotNull(msg); |
| |
| assertTrue(msg instanceof InetDiagMessage); |
| final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg; |
| |
| assertNlMsgHdr(inetDiagMsg.getHeader(), |
| NetlinkConstants.SOCK_DIAG_BY_FAMILY, |
| StructNlMsgHdr.NLM_F_MULTI, |
| 0 /* seq */, |
| 8949 /* pid */); |
| |
| assertEquals(AF_INET6, inetDiagMsg.inetDiagMsg.idiag_family); |
| assertEquals(2, inetDiagMsg.inetDiagMsg.idiag_state); |
| assertEquals(16, inetDiagMsg.inetDiagMsg.idiag_timer); |
| assertEquals(32, inetDiagMsg.inetDiagMsg.idiag_retrans); |
| assertInetDiagSockId(inetDiagMsg.inetDiagMsg.id, |
| new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::3"), 43077), |
| new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::4"), 443), |
| 8 /* ifIndex */, |
| 99 /* cookie */); |
| assertEquals(48, inetDiagMsg.inetDiagMsg.idiag_expires); |
| assertEquals(64, inetDiagMsg.inetDiagMsg.idiag_rqueue); |
| assertEquals(80, inetDiagMsg.inetDiagMsg.idiag_wqueue); |
| assertEquals(12345, inetDiagMsg.inetDiagMsg.idiag_uid); |
| assertEquals(6789, inetDiagMsg.inetDiagMsg.idiag_inode); |
| } |
| |
| private static final byte[] INET_DIAG_MSG_BYTES = |
| HexEncoding.decode(INET_DIAG_MSG_HEX1.toCharArray(), false); |
| |
| @Test |
| public void testParseInetDiagResponse() throws Exception { |
| final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_BYTES); |
| byteBuffer.order(ByteOrder.nativeOrder()); |
| assertInetDiagMsg1(NetlinkMessage.parse(byteBuffer, NETLINK_INET_DIAG)); |
| } |
| |
| |
| private static final byte[] INET_DIAG_MSG_BYTES_MULTIPLE = |
| HexEncoding.decode((INET_DIAG_MSG_HEX1 + INET_DIAG_MSG_HEX2).toCharArray(), false); |
| |
| @Test |
| public void testParseInetDiagResponseMultiple() { |
| final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_BYTES_MULTIPLE); |
| byteBuffer.order(ByteOrder.nativeOrder()); |
| assertInetDiagMsg1(NetlinkMessage.parse(byteBuffer, NETLINK_INET_DIAG)); |
| assertInetDiagMsg2(NetlinkMessage.parse(byteBuffer, NETLINK_INET_DIAG)); |
| } |
| |
| private static final String INET_DIAG_SOCK_ID_V4_MAPPED_V6_HEX = |
| "a845" + // idiag_sport = 43077 |
| "01bb" + // idiag_dport = 443 |
| "00000000000000000000ffffc0000201" + // idiag_src = ::FFFF:192.0.2.1 |
| "00000000000000000000ffffc0000202" + // idiag_dst = ::FFFF:192.0.2.2 |
| "08000000" + // idiag_if = 8 |
| "6300000000000000"; // idiag_cookie = 99 |
| |
| private static final byte[] INET_DIAG_SOCK_ID_V4_MAPPED_V6_BYTES = |
| HexEncoding.decode(INET_DIAG_SOCK_ID_V4_MAPPED_V6_HEX.toCharArray(), false); |
| |
| @Test |
| public void testParseAndPackInetDiagSockIdV4MappedV6() { |
| final ByteBuffer parseByteBuffer = ByteBuffer.wrap(INET_DIAG_SOCK_ID_V4_MAPPED_V6_BYTES); |
| parseByteBuffer.order(ByteOrder.nativeOrder()); |
| final StructInetDiagSockId diagSockId = |
| StructInetDiagSockId.parse(parseByteBuffer, (short) AF_INET6); |
| assertNotNull(diagSockId); |
| |
| final ByteBuffer packByteBuffer = |
| ByteBuffer.allocate(INET_DIAG_SOCK_ID_V4_MAPPED_V6_BYTES.length); |
| diagSockId.pack(packByteBuffer); |
| |
| // Move position to the head since ByteBuffer#equals compares the values from the current |
| // position. |
| parseByteBuffer.position(0); |
| packByteBuffer.position(0); |
| assertEquals(parseByteBuffer, packByteBuffer); |
| } |
| |
| // Hexadecimal representation of InetDiagMessage with v4-mapped v6 address |
| private static final String INET_DIAG_MSG_V4_MAPPED_V6_HEX = |
| // struct nlmsghdr |
| "58000000" + // length = 88 |
| "1400" + // type = SOCK_DIAG_BY_FAMILY |
| "0200" + // flags = NLM_F_MULTI |
| "00000000" + // seqno |
| "f5220000" + // pid |
| // struct inet_diag_msg |
| "0a" + // family = AF_INET6 |
| "01" + // idiag_state = 1 |
| "02" + // idiag_timer = 2 |
| "03" + // idiag_retrans = 3 |
| // inet_diag_sockid |
| "a817" + // idiag_sport = 43031 |
| "960f" + // idiag_dport = 38415 |
| "00000000000000000000ffffc0000201" + // idiag_src = ::FFFF:192.0.2.1 |
| "00000000000000000000ffffc0000202" + // idiag_dst = ::FFFF:192.0.2.2 |
| "07000000" + // idiag_if = 7 |
| "5800000000000000" + // idiag_cookie = 88 |
| "04000000" + // idiag_expires = 4 |
| "05000000" + // idiag_rqueue = 5 |
| "06000000" + // idiag_wqueue = 6 |
| "a3270000" + // idiag_uid = 10147 |
| "A57E1900"; // idiag_inode = 1670821 |
| |
| private static final byte[] INET_DIAG_MSG_V4_MAPPED_V6_BYTES = |
| HexEncoding.decode(INET_DIAG_MSG_V4_MAPPED_V6_HEX.toCharArray(), false); |
| |
| @Test |
| public void testParseInetDiagResponseV4MappedV6() throws Exception { |
| final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_V4_MAPPED_V6_BYTES); |
| byteBuffer.order(ByteOrder.nativeOrder()); |
| final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_INET_DIAG); |
| |
| assertNotNull(msg); |
| assertTrue(msg instanceof InetDiagMessage); |
| final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg; |
| final Inet6Address srcAddr = Inet6Address.getByAddress( |
| null /* host */, SRC_V4_MAPPED_V6_ADDRESS_BYTES, -1 /* scope_id */); |
| final Inet6Address dstAddr = Inet6Address.getByAddress( |
| null /* host */, DST_V4_MAPPED_V6_ADDRESS_BYTES, -1 /* scope_id */); |
| assertInetDiagSockId(inetDiagMsg.inetDiagMsg.id, |
| new InetSocketAddress(srcAddr, 43031), |
| new InetSocketAddress(dstAddr, 38415), |
| 7 /* ifIndex */, |
| 88 /* cookie */); |
| } |
| |
| private void doTestIsLoopback(InetAddress srcAddr, InetAddress dstAddr, boolean expected) { |
| final InetDiagMessage inetDiagMsg = new InetDiagMessage(new StructNlMsgHdr()); |
| inetDiagMsg.inetDiagMsg.id = new StructInetDiagSockId( |
| new InetSocketAddress(srcAddr, 43031), |
| new InetSocketAddress(dstAddr, 38415) |
| ); |
| |
| assertEquals(expected, InetDiagMessage.isLoopback(inetDiagMsg)); |
| } |
| |
| @Test |
| public void testIsLoopback() { |
| doTestIsLoopback( |
| InetAddresses.parseNumericAddress("127.0.0.1"), |
| InetAddresses.parseNumericAddress("192.0.2.1"), |
| true |
| ); |
| doTestIsLoopback( |
| InetAddresses.parseNumericAddress("192.0.2.1"), |
| InetAddresses.parseNumericAddress("127.7.7.7"), |
| true |
| ); |
| doTestIsLoopback( |
| InetAddresses.parseNumericAddress("::1"), |
| InetAddresses.parseNumericAddress("::1"), |
| true |
| ); |
| doTestIsLoopback( |
| InetAddresses.parseNumericAddress("::1"), |
| InetAddresses.parseNumericAddress("2001:db8::1"), |
| true |
| ); |
| } |
| |
| @Test |
| public void testIsLoopbackSameSrcDstAddress() { |
| doTestIsLoopback( |
| InetAddresses.parseNumericAddress("192.0.2.1"), |
| InetAddresses.parseNumericAddress("192.0.2.1"), |
| true |
| ); |
| doTestIsLoopback( |
| InetAddresses.parseNumericAddress("2001:db8::1"), |
| InetAddresses.parseNumericAddress("2001:db8::1"), |
| true |
| ); |
| } |
| |
| @Test |
| public void testIsLoopbackNonLoopbackSocket() { |
| doTestIsLoopback( |
| InetAddresses.parseNumericAddress("192.0.2.1"), |
| InetAddresses.parseNumericAddress("192.0.2.2"), |
| false |
| ); |
| doTestIsLoopback( |
| InetAddresses.parseNumericAddress("2001:db8::1"), |
| InetAddresses.parseNumericAddress("2001:db8::2"), |
| false |
| ); |
| } |
| |
| @Test |
| public void testIsLoopbackV4MappedV6() throws UnknownHostException { |
| // ::FFFF:127.1.2.3 |
| final byte[] addrLoopbackByte = { |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, |
| (byte) 0x7f, (byte) 0x01, (byte) 0x02, (byte) 0x03, |
| }; |
| // ::FFFF:192.0.2.1 |
| final byte[] addrNonLoopbackByte1 = { |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, |
| (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01, |
| }; |
| // ::FFFF:192.0.2.2 |
| final byte[] addrNonLoopbackByte2 = { |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, |
| (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x02, |
| }; |
| |
| final Inet6Address addrLoopback = Inet6Address.getByAddress(null, addrLoopbackByte, -1); |
| final Inet6Address addrNonLoopback1 = |
| Inet6Address.getByAddress(null, addrNonLoopbackByte1, -1); |
| final Inet6Address addrNonLoopback2 = |
| Inet6Address.getByAddress(null, addrNonLoopbackByte2, -1); |
| |
| doTestIsLoopback(addrLoopback, addrNonLoopback1, true); |
| doTestIsLoopback(addrNonLoopback1, addrNonLoopback2, false); |
| doTestIsLoopback(addrNonLoopback1, addrNonLoopback1, true); |
| } |
| |
| private void doTestContainsUid(final int uid, final Set<Range<Integer>> ranges, |
| final boolean expected) { |
| final InetDiagMessage inetDiagMsg = new InetDiagMessage(new StructNlMsgHdr()); |
| inetDiagMsg.inetDiagMsg.idiag_uid = uid; |
| assertEquals(expected, InetDiagMessage.containsUid(inetDiagMsg, ranges)); |
| } |
| |
| @Test |
| public void testContainsUid() { |
| doTestContainsUid(77 /* uid */, |
| new ArraySet<>(List.of(new Range<>(0, 100))), |
| true /* expected */); |
| doTestContainsUid(77 /* uid */, |
| new ArraySet<>(List.of(new Range<>(77, 77), new Range<>(100, 200))), |
| true /* expected */); |
| |
| doTestContainsUid(77 /* uid */, |
| new ArraySet<>(List.of(new Range<>(100, 200))), |
| false /* expected */); |
| doTestContainsUid(77 /* uid */, |
| new ArraySet<>(List.of(new Range<>(0, 76), new Range<>(78, 100))), |
| false /* expected */); |
| } |
| |
| private void doTestIsAdbSocket(final int uid, final boolean expected) { |
| final InetDiagMessage inetDiagMsg = new InetDiagMessage(new StructNlMsgHdr()); |
| inetDiagMsg.inetDiagMsg.idiag_uid = uid; |
| inetDiagMsg.inetDiagMsg.id = new StructInetDiagSockId( |
| new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::1"), 38417), |
| new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::2"), 38415) |
| ); |
| assertEquals(expected, InetDiagMessage.isAdbSocket(inetDiagMsg)); |
| } |
| |
| @Test |
| public void testIsAdbSocket() { |
| final int appUid = 10108; |
| doTestIsAdbSocket(SHELL_UID, true /* expected */); |
| doTestIsAdbSocket(ROOT_UID, false /* expected */); |
| doTestIsAdbSocket(appUid, false /* expected */); |
| } |
| } |