blob: 65e99f82963fca8e042adbb9060fdf602e9ebf17 [file] [log] [blame]
/*
* 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 */);
}
}