Merge "Move shared packages to NetworkStack project"
This commit is contained in:
@@ -20,12 +20,14 @@ java_defaults {
|
||||
srcs: [
|
||||
"src/**/*.java",
|
||||
":framework-tethering-shared-srcs",
|
||||
":net-module-utils-srcs",
|
||||
":services-tethering-shared-srcs",
|
||||
":servicescore-tethering-src",
|
||||
],
|
||||
static_libs: [
|
||||
"androidx.annotation_annotation",
|
||||
"netd_aidl_interface-java",
|
||||
"netlink-client",
|
||||
"networkstack-aidl-interfaces-java",
|
||||
"android.hardware.tetheroffload.control-V1.0-java",
|
||||
"tethering-client",
|
||||
|
||||
@@ -1,38 +1,26 @@
|
||||
java_library_static {
|
||||
name: "services.net",
|
||||
srcs: [
|
||||
":net-module-utils-srcs",
|
||||
":tethering-servicesnet-srcs",
|
||||
"java/**/*.java",
|
||||
],
|
||||
static_libs: [
|
||||
"dnsresolver_aidl_interface-V2-java",
|
||||
"netd_aidl_interface-unstable-java",
|
||||
"netlink-client",
|
||||
"networkstack-client",
|
||||
"tethering-client",
|
||||
],
|
||||
}
|
||||
|
||||
filegroup {
|
||||
name: "services-networkstack-shared-srcs",
|
||||
srcs: [
|
||||
"java/android/net/ip/InterfaceController.java", // TODO: move to NetworkStack with tethering
|
||||
"java/android/net/util/InterfaceParams.java", // TODO: move to NetworkStack with IpServer
|
||||
"java/android/net/shared/*.java",
|
||||
"java/android/net/netlink/*.java",
|
||||
],
|
||||
}
|
||||
|
||||
filegroup {
|
||||
name: "services-tethering-shared-srcs",
|
||||
srcs: [
|
||||
":framework-annotations",
|
||||
"java/android/net/ConnectivityModuleConnector.java",
|
||||
"java/android/net/NetworkStackClient.java",
|
||||
"java/android/net/ip/InterfaceController.java",
|
||||
"java/android/net/netlink/*.java",
|
||||
"java/android/net/util/InterfaceParams.java",
|
||||
"java/android/net/util/NetdService.java",
|
||||
"java/android/net/util/NetworkConstants.java",
|
||||
"java/android/net/util/SharedLog.java"
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,193 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.net.ip;
|
||||
|
||||
import android.net.INetd;
|
||||
import android.net.InterfaceConfigurationParcel;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.util.SharedLog;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceSpecificException;
|
||||
import android.system.OsConstants;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
|
||||
|
||||
/**
|
||||
* Encapsulates the multiple IP configuration operations performed on an interface.
|
||||
*
|
||||
* TODO: refactor/eliminate the redundant ways to set and clear addresses.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class InterfaceController {
|
||||
private final static boolean DBG = false;
|
||||
|
||||
private final String mIfName;
|
||||
private final INetd mNetd;
|
||||
private final SharedLog mLog;
|
||||
|
||||
public InterfaceController(String ifname, INetd netd, SharedLog log) {
|
||||
mIfName = ifname;
|
||||
mNetd = netd;
|
||||
mLog = log;
|
||||
}
|
||||
|
||||
private boolean setInterfaceAddress(LinkAddress addr) {
|
||||
final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel();
|
||||
ifConfig.ifName = mIfName;
|
||||
ifConfig.ipv4Addr = addr.getAddress().getHostAddress();
|
||||
ifConfig.prefixLength = addr.getPrefixLength();
|
||||
ifConfig.hwAddr = "";
|
||||
ifConfig.flags = new String[0];
|
||||
try {
|
||||
mNetd.interfaceSetCfg(ifConfig);
|
||||
} catch (RemoteException | ServiceSpecificException e) {
|
||||
logError("Setting IPv4 address to %s/%d failed: %s",
|
||||
ifConfig.ipv4Addr, ifConfig.prefixLength, e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the IPv4 address of the interface.
|
||||
*/
|
||||
public boolean setIPv4Address(LinkAddress address) {
|
||||
if (!(address.getAddress() instanceof Inet4Address)) {
|
||||
return false;
|
||||
}
|
||||
return setInterfaceAddress(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the IPv4Address of the interface.
|
||||
*/
|
||||
public boolean clearIPv4Address() {
|
||||
return setInterfaceAddress(new LinkAddress("0.0.0.0/0"));
|
||||
}
|
||||
|
||||
private boolean setEnableIPv6(boolean enabled) {
|
||||
try {
|
||||
mNetd.interfaceSetEnableIPv6(mIfName, enabled);
|
||||
} catch (RemoteException | ServiceSpecificException e) {
|
||||
logError("%s IPv6 failed: %s", (enabled ? "enabling" : "disabling"), e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable IPv6 on the interface.
|
||||
*/
|
||||
public boolean enableIPv6() {
|
||||
return setEnableIPv6(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable IPv6 on the interface.
|
||||
*/
|
||||
public boolean disableIPv6() {
|
||||
return setEnableIPv6(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable IPv6 privacy extensions on the interface.
|
||||
* @param enabled Whether the extensions should be enabled.
|
||||
*/
|
||||
public boolean setIPv6PrivacyExtensions(boolean enabled) {
|
||||
try {
|
||||
mNetd.interfaceSetIPv6PrivacyExtensions(mIfName, enabled);
|
||||
} catch (RemoteException | ServiceSpecificException e) {
|
||||
logError("error %s IPv6 privacy extensions: %s",
|
||||
(enabled ? "enabling" : "disabling"), e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set IPv6 address generation mode on the interface.
|
||||
*
|
||||
* <p>IPv6 should be disabled before changing the mode.
|
||||
*/
|
||||
public boolean setIPv6AddrGenModeIfSupported(int mode) {
|
||||
try {
|
||||
mNetd.setIPv6AddrGenMode(mIfName, mode);
|
||||
} catch (RemoteException e) {
|
||||
logError("Unable to set IPv6 addrgen mode: %s", e);
|
||||
return false;
|
||||
} catch (ServiceSpecificException e) {
|
||||
if (e.errorCode != OsConstants.EOPNOTSUPP) {
|
||||
logError("Unable to set IPv6 addrgen mode: %s", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an address to the interface.
|
||||
*/
|
||||
public boolean addAddress(LinkAddress addr) {
|
||||
return addAddress(addr.getAddress(), addr.getPrefixLength());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an address to the interface.
|
||||
*/
|
||||
public boolean addAddress(InetAddress ip, int prefixLen) {
|
||||
try {
|
||||
mNetd.interfaceAddAddress(mIfName, ip.getHostAddress(), prefixLen);
|
||||
} catch (ServiceSpecificException | RemoteException e) {
|
||||
logError("failed to add %s/%d: %s", ip, prefixLen, e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an address from the interface.
|
||||
*/
|
||||
public boolean removeAddress(InetAddress ip, int prefixLen) {
|
||||
try {
|
||||
mNetd.interfaceDelAddress(mIfName, ip.getHostAddress(), prefixLen);
|
||||
} catch (ServiceSpecificException | RemoteException e) {
|
||||
logError("failed to remove %s/%d: %s", ip, prefixLen, e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all addresses from the interface.
|
||||
*/
|
||||
public boolean clearAllAddresses() {
|
||||
try {
|
||||
mNetd.interfaceClearAddrs(mIfName);
|
||||
} catch (Exception e) {
|
||||
logError("Failed to clear addresses: %s", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void logError(String fmt, Object... args) {
|
||||
mLog.e(String.format(fmt, args));
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.net.netlink;
|
||||
|
||||
import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
|
||||
import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
|
||||
import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
|
||||
|
||||
import static java.nio.ByteOrder.BIG_ENDIAN;
|
||||
|
||||
import android.system.OsConstants;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
|
||||
/**
|
||||
* A NetlinkMessage subclass for netlink conntrack messages.
|
||||
*
|
||||
* see also: <linux_src>/include/uapi/linux/netfilter/nfnetlink_conntrack.h
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class ConntrackMessage extends NetlinkMessage {
|
||||
public static final int STRUCT_SIZE = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE;
|
||||
|
||||
public static final short NFNL_SUBSYS_CTNETLINK = 1;
|
||||
public static final short IPCTNL_MSG_CT_NEW = 0;
|
||||
|
||||
// enum ctattr_type
|
||||
public static final short CTA_TUPLE_ORIG = 1;
|
||||
public static final short CTA_TUPLE_REPLY = 2;
|
||||
public static final short CTA_TIMEOUT = 7;
|
||||
|
||||
// enum ctattr_tuple
|
||||
public static final short CTA_TUPLE_IP = 1;
|
||||
public static final short CTA_TUPLE_PROTO = 2;
|
||||
|
||||
// enum ctattr_ip
|
||||
public static final short CTA_IP_V4_SRC = 1;
|
||||
public static final short CTA_IP_V4_DST = 2;
|
||||
|
||||
// enum ctattr_l4proto
|
||||
public static final short CTA_PROTO_NUM = 1;
|
||||
public static final short CTA_PROTO_SRC_PORT = 2;
|
||||
public static final short CTA_PROTO_DST_PORT = 3;
|
||||
|
||||
public static byte[] newIPv4TimeoutUpdateRequest(
|
||||
int proto, Inet4Address src, int sport, Inet4Address dst, int dport, int timeoutSec) {
|
||||
// *** STYLE WARNING ***
|
||||
//
|
||||
// Code below this point uses extra block indentation to highlight the
|
||||
// packing of nested tuple netlink attribute types.
|
||||
final StructNlAttr ctaTupleOrig = new StructNlAttr(CTA_TUPLE_ORIG,
|
||||
new StructNlAttr(CTA_TUPLE_IP,
|
||||
new StructNlAttr(CTA_IP_V4_SRC, src),
|
||||
new StructNlAttr(CTA_IP_V4_DST, dst)),
|
||||
new StructNlAttr(CTA_TUPLE_PROTO,
|
||||
new StructNlAttr(CTA_PROTO_NUM, (byte) proto),
|
||||
new StructNlAttr(CTA_PROTO_SRC_PORT, (short) sport, BIG_ENDIAN),
|
||||
new StructNlAttr(CTA_PROTO_DST_PORT, (short) dport, BIG_ENDIAN)));
|
||||
|
||||
final StructNlAttr ctaTimeout = new StructNlAttr(CTA_TIMEOUT, timeoutSec, BIG_ENDIAN);
|
||||
|
||||
final int payloadLength = ctaTupleOrig.getAlignedLength() + ctaTimeout.getAlignedLength();
|
||||
final byte[] bytes = new byte[STRUCT_SIZE + payloadLength];
|
||||
final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
|
||||
byteBuffer.order(ByteOrder.nativeOrder());
|
||||
|
||||
final ConntrackMessage ctmsg = new ConntrackMessage();
|
||||
ctmsg.mHeader.nlmsg_len = bytes.length;
|
||||
ctmsg.mHeader.nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_NEW;
|
||||
ctmsg.mHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE;
|
||||
ctmsg.mHeader.nlmsg_seq = 1;
|
||||
ctmsg.pack(byteBuffer);
|
||||
|
||||
ctaTupleOrig.pack(byteBuffer);
|
||||
ctaTimeout.pack(byteBuffer);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
protected StructNfGenMsg mNfGenMsg;
|
||||
|
||||
private ConntrackMessage() {
|
||||
super(new StructNlMsgHdr());
|
||||
mNfGenMsg = new StructNfGenMsg((byte) OsConstants.AF_INET);
|
||||
}
|
||||
|
||||
public void pack(ByteBuffer byteBuffer) {
|
||||
mHeader.pack(byteBuffer);
|
||||
mNfGenMsg.pack(byteBuffer);
|
||||
}
|
||||
}
|
||||
@@ -1,221 +0,0 @@
|
||||
/*
|
||||
* 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 android.net.netlink;
|
||||
|
||||
import static android.net.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY;
|
||||
import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
|
||||
import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
|
||||
import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
|
||||
import static android.os.Process.INVALID_UID;
|
||||
import static android.system.OsConstants.AF_INET;
|
||||
import static android.system.OsConstants.AF_INET6;
|
||||
import static android.system.OsConstants.IPPROTO_UDP;
|
||||
import static android.system.OsConstants.NETLINK_INET_DIAG;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.net.util.SocketUtils;
|
||||
import android.system.ErrnoException;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* A NetlinkMessage subclass for netlink inet_diag messages.
|
||||
*
|
||||
* see also: <linux_src>/include/uapi/linux/inet_diag.h
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class InetDiagMessage extends NetlinkMessage {
|
||||
public static final String TAG = "InetDiagMessage";
|
||||
private static final int TIMEOUT_MS = 500;
|
||||
|
||||
public static byte[] InetDiagReqV2(int protocol, InetSocketAddress local,
|
||||
InetSocketAddress remote, int family, short flags) {
|
||||
return InetDiagReqV2(protocol, local, remote, family, flags, 0 /* pad */,
|
||||
0 /* idiagExt */, StructInetDiagReqV2.INET_DIAG_REQ_V2_ALL_STATES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an inet_diag_req_v2 message. This method will throw {@code NullPointerException}
|
||||
* if local and remote are not both null or both non-null.
|
||||
*
|
||||
* @param protocol the request protocol type. This should be set to one of IPPROTO_TCP,
|
||||
* IPPROTO_UDP, or IPPROTO_UDPLITE.
|
||||
* @param local local socket address of the target socket. This will be packed into a
|
||||
* {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of
|
||||
* local or remote address is null.
|
||||
* @param remote remote socket address of the target socket. This will be packed into a
|
||||
* {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of
|
||||
* local or remote address is null.
|
||||
* @param family the ip family of the request message. This should be set to either AF_INET or
|
||||
* AF_INET6 for IPv4 or IPv6 sockets respectively.
|
||||
* @param flags message flags. See <linux_src>/include/uapi/linux/netlink.h.
|
||||
* @param pad for raw socket protocol specification.
|
||||
* @param idiagExt a set of flags defining what kind of extended information to report.
|
||||
* @param state a bit mask that defines a filter of socket states.
|
||||
*
|
||||
* @return bytes array representation of the message
|
||||
**/
|
||||
public static byte[] InetDiagReqV2(int protocol, @Nullable InetSocketAddress local,
|
||||
@Nullable InetSocketAddress remote, int family, short flags, int pad, int idiagExt,
|
||||
int state) throws NullPointerException {
|
||||
final byte[] bytes = new byte[StructNlMsgHdr.STRUCT_SIZE + StructInetDiagReqV2.STRUCT_SIZE];
|
||||
final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
|
||||
byteBuffer.order(ByteOrder.nativeOrder());
|
||||
|
||||
final StructNlMsgHdr nlMsgHdr = new StructNlMsgHdr();
|
||||
nlMsgHdr.nlmsg_len = bytes.length;
|
||||
nlMsgHdr.nlmsg_type = SOCK_DIAG_BY_FAMILY;
|
||||
nlMsgHdr.nlmsg_flags = flags;
|
||||
nlMsgHdr.pack(byteBuffer);
|
||||
final StructInetDiagReqV2 inetDiagReqV2 =
|
||||
new StructInetDiagReqV2(protocol, local, remote, family, pad, idiagExt, state);
|
||||
|
||||
inetDiagReqV2.pack(byteBuffer);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public StructInetDiagMsg mStructInetDiagMsg;
|
||||
|
||||
private InetDiagMessage(StructNlMsgHdr header) {
|
||||
super(header);
|
||||
mStructInetDiagMsg = new StructInetDiagMsg();
|
||||
}
|
||||
|
||||
public static InetDiagMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
|
||||
final InetDiagMessage msg = new InetDiagMessage(header);
|
||||
msg.mStructInetDiagMsg = StructInetDiagMsg.parse(byteBuffer);
|
||||
return msg;
|
||||
}
|
||||
|
||||
private static int lookupUidByFamily(int protocol, InetSocketAddress local,
|
||||
InetSocketAddress remote, int family, short flags,
|
||||
FileDescriptor fd)
|
||||
throws ErrnoException, InterruptedIOException {
|
||||
byte[] msg = InetDiagReqV2(protocol, local, remote, family, flags);
|
||||
NetlinkSocket.sendMessage(fd, msg, 0, msg.length, TIMEOUT_MS);
|
||||
ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT_MS);
|
||||
|
||||
final NetlinkMessage nlMsg = NetlinkMessage.parse(response);
|
||||
final StructNlMsgHdr hdr = nlMsg.getHeader();
|
||||
if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) {
|
||||
return INVALID_UID;
|
||||
}
|
||||
if (nlMsg instanceof InetDiagMessage) {
|
||||
return ((InetDiagMessage) nlMsg).mStructInetDiagMsg.idiag_uid;
|
||||
}
|
||||
return INVALID_UID;
|
||||
}
|
||||
|
||||
private static final int FAMILY[] = {AF_INET6, AF_INET};
|
||||
|
||||
private static int lookupUid(int protocol, InetSocketAddress local,
|
||||
InetSocketAddress remote, FileDescriptor fd)
|
||||
throws ErrnoException, InterruptedIOException {
|
||||
int uid;
|
||||
|
||||
for (int family : FAMILY) {
|
||||
/**
|
||||
* For exact match lookup, swap local and remote for UDP lookups due to kernel
|
||||
* bug which will not be fixed. See aosp/755889 and
|
||||
* https://www.mail-archive.com/netdev@vger.kernel.org/msg248638.html
|
||||
*/
|
||||
if (protocol == IPPROTO_UDP) {
|
||||
uid = lookupUidByFamily(protocol, remote, local, family, NLM_F_REQUEST, fd);
|
||||
} else {
|
||||
uid = lookupUidByFamily(protocol, local, remote, family, NLM_F_REQUEST, fd);
|
||||
}
|
||||
if (uid != INVALID_UID) {
|
||||
return uid;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For UDP it's possible for a socket to send packets to arbitrary destinations, even if the
|
||||
* socket is not connected (and even if the socket is connected to a different destination).
|
||||
* If we want this API to work for such packets, then on miss we need to do a second lookup
|
||||
* with only the local address and port filled in.
|
||||
* Always use flags == NLM_F_REQUEST | NLM_F_DUMP for wildcard.
|
||||
*/
|
||||
if (protocol == IPPROTO_UDP) {
|
||||
try {
|
||||
InetSocketAddress wildcard = new InetSocketAddress(
|
||||
Inet6Address.getByName("::"), 0);
|
||||
uid = lookupUidByFamily(protocol, local, wildcard, AF_INET6,
|
||||
(short) (NLM_F_REQUEST | NLM_F_DUMP), fd);
|
||||
if (uid != INVALID_UID) {
|
||||
return uid;
|
||||
}
|
||||
wildcard = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), 0);
|
||||
uid = lookupUidByFamily(protocol, local, wildcard, AF_INET,
|
||||
(short) (NLM_F_REQUEST | NLM_F_DUMP), fd);
|
||||
if (uid != INVALID_UID) {
|
||||
return uid;
|
||||
}
|
||||
} catch (UnknownHostException e) {
|
||||
Log.e(TAG, e.toString());
|
||||
}
|
||||
}
|
||||
return INVALID_UID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use an inet_diag socket to look up the UID associated with the input local and remote
|
||||
* address/port and protocol of a connection.
|
||||
*/
|
||||
public static int getConnectionOwnerUid(int protocol, InetSocketAddress local,
|
||||
InetSocketAddress remote) {
|
||||
int uid = INVALID_UID;
|
||||
FileDescriptor fd = null;
|
||||
try {
|
||||
fd = NetlinkSocket.forProto(NETLINK_INET_DIAG);
|
||||
NetlinkSocket.connectToKernel(fd);
|
||||
uid = lookupUid(protocol, local, remote, fd);
|
||||
} catch (ErrnoException | SocketException | IllegalArgumentException
|
||||
| InterruptedIOException e) {
|
||||
Log.e(TAG, e.toString());
|
||||
} finally {
|
||||
if (fd != null) {
|
||||
try {
|
||||
SocketUtils.closeSocket(fd);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
return uid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InetDiagMessage{ "
|
||||
+ "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, "
|
||||
+ "inet_diag_msg{"
|
||||
+ (mStructInetDiagMsg == null ? "" : mStructInetDiagMsg.toString()) + "} "
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 android.net.netlink;
|
||||
|
||||
import android.system.OsConstants;
|
||||
import com.android.internal.util.HexDump;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
||||
/**
|
||||
* Various constants and static helper methods for netlink communications.
|
||||
*
|
||||
* Values taken from:
|
||||
*
|
||||
* <linux_src>/include/uapi/linux/netlink.h
|
||||
* <linux_src>/include/uapi/linux/rtnetlink.h
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class NetlinkConstants {
|
||||
private NetlinkConstants() {}
|
||||
|
||||
public static final int NLA_ALIGNTO = 4;
|
||||
|
||||
public static final int alignedLengthOf(short length) {
|
||||
final int intLength = (int) length & 0xffff;
|
||||
return alignedLengthOf(intLength);
|
||||
}
|
||||
|
||||
public static final int alignedLengthOf(int length) {
|
||||
if (length <= 0) { return 0; }
|
||||
return (((length + NLA_ALIGNTO - 1) / NLA_ALIGNTO) * NLA_ALIGNTO);
|
||||
}
|
||||
|
||||
public static String stringForAddressFamily(int family) {
|
||||
if (family == OsConstants.AF_INET) { return "AF_INET"; }
|
||||
if (family == OsConstants.AF_INET6) { return "AF_INET6"; }
|
||||
if (family == OsConstants.AF_NETLINK) { return "AF_NETLINK"; }
|
||||
return String.valueOf(family);
|
||||
}
|
||||
|
||||
public static String stringForProtocol(int protocol) {
|
||||
if (protocol == OsConstants.IPPROTO_TCP) { return "IPPROTO_TCP"; }
|
||||
if (protocol == OsConstants.IPPROTO_UDP) { return "IPPROTO_UDP"; }
|
||||
return String.valueOf(protocol);
|
||||
}
|
||||
|
||||
public static String hexify(byte[] bytes) {
|
||||
if (bytes == null) { return "(null)"; }
|
||||
return HexDump.toHexString(bytes);
|
||||
}
|
||||
|
||||
public static String hexify(ByteBuffer buffer) {
|
||||
if (buffer == null) { return "(null)"; }
|
||||
return HexDump.toHexString(
|
||||
buffer.array(), buffer.position(), buffer.remaining());
|
||||
}
|
||||
|
||||
// Known values for struct nlmsghdr nlm_type.
|
||||
public static final short NLMSG_NOOP = 1; // Nothing
|
||||
public static final short NLMSG_ERROR = 2; // Error
|
||||
public static final short NLMSG_DONE = 3; // End of a dump
|
||||
public static final short NLMSG_OVERRUN = 4; // Data lost
|
||||
public static final short NLMSG_MAX_RESERVED = 15; // Max reserved value
|
||||
|
||||
public static final short RTM_NEWLINK = 16;
|
||||
public static final short RTM_DELLINK = 17;
|
||||
public static final short RTM_GETLINK = 18;
|
||||
public static final short RTM_SETLINK = 19;
|
||||
public static final short RTM_NEWADDR = 20;
|
||||
public static final short RTM_DELADDR = 21;
|
||||
public static final short RTM_GETADDR = 22;
|
||||
public static final short RTM_NEWROUTE = 24;
|
||||
public static final short RTM_DELROUTE = 25;
|
||||
public static final short RTM_GETROUTE = 26;
|
||||
public static final short RTM_NEWNEIGH = 28;
|
||||
public static final short RTM_DELNEIGH = 29;
|
||||
public static final short RTM_GETNEIGH = 30;
|
||||
public static final short RTM_NEWRULE = 32;
|
||||
public static final short RTM_DELRULE = 33;
|
||||
public static final short RTM_GETRULE = 34;
|
||||
public static final short RTM_NEWNDUSEROPT = 68;
|
||||
|
||||
/* see <linux_src>/include/uapi/linux/sock_diag.h */
|
||||
public static final short SOCK_DIAG_BY_FAMILY = 20;
|
||||
|
||||
public static String stringForNlMsgType(short nlm_type) {
|
||||
switch (nlm_type) {
|
||||
case NLMSG_NOOP: return "NLMSG_NOOP";
|
||||
case NLMSG_ERROR: return "NLMSG_ERROR";
|
||||
case NLMSG_DONE: return "NLMSG_DONE";
|
||||
case NLMSG_OVERRUN: return "NLMSG_OVERRUN";
|
||||
case RTM_NEWLINK: return "RTM_NEWLINK";
|
||||
case RTM_DELLINK: return "RTM_DELLINK";
|
||||
case RTM_GETLINK: return "RTM_GETLINK";
|
||||
case RTM_SETLINK: return "RTM_SETLINK";
|
||||
case RTM_NEWADDR: return "RTM_NEWADDR";
|
||||
case RTM_DELADDR: return "RTM_DELADDR";
|
||||
case RTM_GETADDR: return "RTM_GETADDR";
|
||||
case RTM_NEWROUTE: return "RTM_NEWROUTE";
|
||||
case RTM_DELROUTE: return "RTM_DELROUTE";
|
||||
case RTM_GETROUTE: return "RTM_GETROUTE";
|
||||
case RTM_NEWNEIGH: return "RTM_NEWNEIGH";
|
||||
case RTM_DELNEIGH: return "RTM_DELNEIGH";
|
||||
case RTM_GETNEIGH: return "RTM_GETNEIGH";
|
||||
case RTM_NEWRULE: return "RTM_NEWRULE";
|
||||
case RTM_DELRULE: return "RTM_DELRULE";
|
||||
case RTM_GETRULE: return "RTM_GETRULE";
|
||||
case RTM_NEWNDUSEROPT: return "RTM_NEWNDUSEROPT";
|
||||
default:
|
||||
return "unknown RTM type: " + String.valueOf(nlm_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 android.net.netlink;
|
||||
|
||||
import android.net.netlink.StructNlMsgHdr;
|
||||
import android.net.netlink.NetlinkMessage;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
||||
/**
|
||||
* A NetlinkMessage subclass for netlink error messages.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class NetlinkErrorMessage extends NetlinkMessage {
|
||||
|
||||
public static NetlinkErrorMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
|
||||
final NetlinkErrorMessage errorMsg = new NetlinkErrorMessage(header);
|
||||
|
||||
errorMsg.mNlMsgErr = StructNlMsgErr.parse(byteBuffer);
|
||||
if (errorMsg.mNlMsgErr == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
private StructNlMsgErr mNlMsgErr;
|
||||
|
||||
NetlinkErrorMessage(StructNlMsgHdr header) {
|
||||
super(header);
|
||||
mNlMsgErr = null;
|
||||
}
|
||||
|
||||
public StructNlMsgErr getNlMsgError() {
|
||||
return mNlMsgErr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NetlinkErrorMessage{ "
|
||||
+ "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, "
|
||||
+ "nlmsgerr{" + (mNlMsgErr == null ? "" : mNlMsgErr.toString()) + "} "
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 android.net.netlink;
|
||||
|
||||
import android.net.netlink.NetlinkConstants;
|
||||
import android.net.netlink.NetlinkErrorMessage;
|
||||
import android.net.netlink.RtNetlinkNeighborMessage;
|
||||
import android.net.netlink.StructNlAttr;
|
||||
import android.net.netlink.StructNlMsgHdr;
|
||||
import android.util.Log;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
||||
/**
|
||||
* NetlinkMessage base class for other, more specific netlink message types.
|
||||
*
|
||||
* Classes that extend NetlinkMessage should:
|
||||
* - implement a public static parse(StructNlMsgHdr, ByteBuffer) method
|
||||
* - returning either null (parse errors) or a new object of the subclass
|
||||
* type (cast-able to NetlinkMessage)
|
||||
*
|
||||
* NetlinkMessage.parse() should be updated to know which nlmsg_type values
|
||||
* correspond with which message subclasses.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class NetlinkMessage {
|
||||
private final static String TAG = "NetlinkMessage";
|
||||
|
||||
public static NetlinkMessage parse(ByteBuffer byteBuffer) {
|
||||
final int startPosition = (byteBuffer != null) ? byteBuffer.position() : -1;
|
||||
final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(byteBuffer);
|
||||
if (nlmsghdr == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int payloadLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len);
|
||||
payloadLength -= StructNlMsgHdr.STRUCT_SIZE;
|
||||
if (payloadLength < 0 || payloadLength > byteBuffer.remaining()) {
|
||||
// Malformed message or runt buffer. Pretend the buffer was consumed.
|
||||
byteBuffer.position(byteBuffer.limit());
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (nlmsghdr.nlmsg_type) {
|
||||
//case NetlinkConstants.NLMSG_NOOP:
|
||||
case NetlinkConstants.NLMSG_ERROR:
|
||||
return (NetlinkMessage) NetlinkErrorMessage.parse(nlmsghdr, byteBuffer);
|
||||
case NetlinkConstants.NLMSG_DONE:
|
||||
byteBuffer.position(byteBuffer.position() + payloadLength);
|
||||
return new NetlinkMessage(nlmsghdr);
|
||||
//case NetlinkConstants.NLMSG_OVERRUN:
|
||||
case NetlinkConstants.RTM_NEWNEIGH:
|
||||
case NetlinkConstants.RTM_DELNEIGH:
|
||||
case NetlinkConstants.RTM_GETNEIGH:
|
||||
return (NetlinkMessage) RtNetlinkNeighborMessage.parse(nlmsghdr, byteBuffer);
|
||||
case NetlinkConstants.SOCK_DIAG_BY_FAMILY:
|
||||
return (NetlinkMessage) InetDiagMessage.parse(nlmsghdr, byteBuffer);
|
||||
default:
|
||||
if (nlmsghdr.nlmsg_type <= NetlinkConstants.NLMSG_MAX_RESERVED) {
|
||||
// Netlink control message. Just parse the header for now,
|
||||
// pretending the whole message was consumed.
|
||||
byteBuffer.position(byteBuffer.position() + payloadLength);
|
||||
return new NetlinkMessage(nlmsghdr);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected StructNlMsgHdr mHeader;
|
||||
|
||||
public NetlinkMessage(StructNlMsgHdr nlmsghdr) {
|
||||
mHeader = nlmsghdr;
|
||||
}
|
||||
|
||||
public StructNlMsgHdr getHeader() {
|
||||
return mHeader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NetlinkMessage{" + (mHeader == null ? "" : mHeader.toString()) + "}";
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 android.net.netlink;
|
||||
|
||||
import static android.net.util.SocketUtils.makeNetlinkSocketAddress;
|
||||
import static android.system.OsConstants.AF_NETLINK;
|
||||
import static android.system.OsConstants.EIO;
|
||||
import static android.system.OsConstants.EPROTO;
|
||||
import static android.system.OsConstants.ETIMEDOUT;
|
||||
import static android.system.OsConstants.SOCK_DGRAM;
|
||||
import static android.system.OsConstants.SOL_SOCKET;
|
||||
import static android.system.OsConstants.SO_RCVBUF;
|
||||
import static android.system.OsConstants.SO_RCVTIMEO;
|
||||
import static android.system.OsConstants.SO_SNDTIMEO;
|
||||
|
||||
import android.net.util.SocketUtils;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.system.StructTimeval;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.SocketException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
|
||||
/**
|
||||
* NetlinkSocket
|
||||
*
|
||||
* A small static class to assist with AF_NETLINK socket operations.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class NetlinkSocket {
|
||||
private static final String TAG = "NetlinkSocket";
|
||||
|
||||
public static final int DEFAULT_RECV_BUFSIZE = 8 * 1024;
|
||||
public static final int SOCKET_RECV_BUFSIZE = 64 * 1024;
|
||||
|
||||
public static void sendOneShotKernelMessage(int nlProto, byte[] msg) throws ErrnoException {
|
||||
final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage";
|
||||
final long IO_TIMEOUT = 300L;
|
||||
|
||||
final FileDescriptor fd = forProto(nlProto);
|
||||
|
||||
try {
|
||||
connectToKernel(fd);
|
||||
sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT);
|
||||
final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT);
|
||||
// recvMessage() guaranteed to not return null if it did not throw.
|
||||
final NetlinkMessage response = NetlinkMessage.parse(bytes);
|
||||
if (response != null && response instanceof NetlinkErrorMessage &&
|
||||
(((NetlinkErrorMessage) response).getNlMsgError() != null)) {
|
||||
final int errno = ((NetlinkErrorMessage) response).getNlMsgError().error;
|
||||
if (errno != 0) {
|
||||
// TODO: consider ignoring EINVAL (-22), which appears to be
|
||||
// normal when probing a neighbor for which the kernel does
|
||||
// not already have / no longer has a link layer address.
|
||||
Log.e(TAG, errPrefix + ", errmsg=" + response.toString());
|
||||
// Note: convert kernel errnos (negative) into userspace errnos (positive).
|
||||
throw new ErrnoException(response.toString(), Math.abs(errno));
|
||||
}
|
||||
} else {
|
||||
final String errmsg;
|
||||
if (response == null) {
|
||||
bytes.position(0);
|
||||
errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes);
|
||||
} else {
|
||||
errmsg = response.toString();
|
||||
}
|
||||
Log.e(TAG, errPrefix + ", errmsg=" + errmsg);
|
||||
throw new ErrnoException(errmsg, EPROTO);
|
||||
}
|
||||
} catch (InterruptedIOException e) {
|
||||
Log.e(TAG, errPrefix, e);
|
||||
throw new ErrnoException(errPrefix, ETIMEDOUT, e);
|
||||
} catch (SocketException e) {
|
||||
Log.e(TAG, errPrefix, e);
|
||||
throw new ErrnoException(errPrefix, EIO, e);
|
||||
} finally {
|
||||
try {
|
||||
SocketUtils.closeSocket(fd);
|
||||
} catch (IOException e) {
|
||||
// Nothing we can do here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static FileDescriptor forProto(int nlProto) throws ErrnoException {
|
||||
final FileDescriptor fd = Os.socket(AF_NETLINK, SOCK_DGRAM, nlProto);
|
||||
Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, SOCKET_RECV_BUFSIZE);
|
||||
return fd;
|
||||
}
|
||||
|
||||
public static void connectToKernel(FileDescriptor fd) throws ErrnoException, SocketException {
|
||||
Os.connect(fd, makeNetlinkSocketAddress(0, 0));
|
||||
}
|
||||
|
||||
private static void checkTimeout(long timeoutMs) {
|
||||
if (timeoutMs < 0) {
|
||||
throw new IllegalArgumentException("Negative timeouts not permitted");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait up to |timeoutMs| (or until underlying socket error) for a
|
||||
* netlink message of at most |bufsize| size.
|
||||
*
|
||||
* Multi-threaded calls with different timeouts will cause unexpected results.
|
||||
*/
|
||||
public static ByteBuffer recvMessage(FileDescriptor fd, int bufsize, long timeoutMs)
|
||||
throws ErrnoException, IllegalArgumentException, InterruptedIOException {
|
||||
checkTimeout(timeoutMs);
|
||||
|
||||
Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs));
|
||||
|
||||
ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize);
|
||||
int length = Os.read(fd, byteBuffer);
|
||||
if (length == bufsize) {
|
||||
Log.w(TAG, "maximum read");
|
||||
}
|
||||
byteBuffer.position(0);
|
||||
byteBuffer.limit(length);
|
||||
byteBuffer.order(ByteOrder.nativeOrder());
|
||||
return byteBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to a peer to which this socket has previously connected,
|
||||
* waiting at most |timeoutMs| milliseconds for the send to complete.
|
||||
*
|
||||
* Multi-threaded calls with different timeouts will cause unexpected results.
|
||||
*/
|
||||
public static int sendMessage(
|
||||
FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs)
|
||||
throws ErrnoException, IllegalArgumentException, InterruptedIOException {
|
||||
checkTimeout(timeoutMs);
|
||||
Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs));
|
||||
return Os.write(fd, bytes, offset, count);
|
||||
}
|
||||
}
|
||||
@@ -1,251 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 android.net.netlink;
|
||||
|
||||
import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
|
||||
import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
|
||||
import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
|
||||
import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
|
||||
|
||||
import android.net.netlink.StructNdaCacheInfo;
|
||||
import android.net.netlink.StructNdMsg;
|
||||
import android.net.netlink.StructNlAttr;
|
||||
import android.net.netlink.StructNlMsgHdr;
|
||||
import android.net.netlink.NetlinkMessage;
|
||||
import android.system.OsConstants;
|
||||
import android.util.Log;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.Inet6Address;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
|
||||
/**
|
||||
* A NetlinkMessage subclass for rtnetlink neighbor messages.
|
||||
*
|
||||
* see also: <linux_src>/include/uapi/linux/neighbour.h
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class RtNetlinkNeighborMessage extends NetlinkMessage {
|
||||
public static final short NDA_UNSPEC = 0;
|
||||
public static final short NDA_DST = 1;
|
||||
public static final short NDA_LLADDR = 2;
|
||||
public static final short NDA_CACHEINFO = 3;
|
||||
public static final short NDA_PROBES = 4;
|
||||
public static final short NDA_VLAN = 5;
|
||||
public static final short NDA_PORT = 6;
|
||||
public static final short NDA_VNI = 7;
|
||||
public static final short NDA_IFINDEX = 8;
|
||||
public static final short NDA_MASTER = 9;
|
||||
|
||||
private static StructNlAttr findNextAttrOfType(short attrType, ByteBuffer byteBuffer) {
|
||||
while (byteBuffer != null && byteBuffer.remaining() > 0) {
|
||||
final StructNlAttr nlAttr = StructNlAttr.peek(byteBuffer);
|
||||
if (nlAttr == null) {
|
||||
break;
|
||||
}
|
||||
if (nlAttr.nla_type == attrType) {
|
||||
return StructNlAttr.parse(byteBuffer);
|
||||
}
|
||||
if (byteBuffer.remaining() < nlAttr.getAlignedLength()) {
|
||||
break;
|
||||
}
|
||||
byteBuffer.position(byteBuffer.position() + nlAttr.getAlignedLength());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static RtNetlinkNeighborMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
|
||||
final RtNetlinkNeighborMessage neighMsg = new RtNetlinkNeighborMessage(header);
|
||||
|
||||
neighMsg.mNdmsg = StructNdMsg.parse(byteBuffer);
|
||||
if (neighMsg.mNdmsg == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Some of these are message-type dependent, and not always present.
|
||||
final int baseOffset = byteBuffer.position();
|
||||
StructNlAttr nlAttr = findNextAttrOfType(NDA_DST, byteBuffer);
|
||||
if (nlAttr != null) {
|
||||
neighMsg.mDestination = nlAttr.getValueAsInetAddress();
|
||||
}
|
||||
|
||||
byteBuffer.position(baseOffset);
|
||||
nlAttr = findNextAttrOfType(NDA_LLADDR, byteBuffer);
|
||||
if (nlAttr != null) {
|
||||
neighMsg.mLinkLayerAddr = nlAttr.nla_value;
|
||||
}
|
||||
|
||||
byteBuffer.position(baseOffset);
|
||||
nlAttr = findNextAttrOfType(NDA_PROBES, byteBuffer);
|
||||
if (nlAttr != null) {
|
||||
neighMsg.mNumProbes = nlAttr.getValueAsInt(0);
|
||||
}
|
||||
|
||||
byteBuffer.position(baseOffset);
|
||||
nlAttr = findNextAttrOfType(NDA_CACHEINFO, byteBuffer);
|
||||
if (nlAttr != null) {
|
||||
neighMsg.mCacheInfo = StructNdaCacheInfo.parse(nlAttr.getValueAsByteBuffer());
|
||||
}
|
||||
|
||||
final int kMinConsumed = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
|
||||
final int kAdditionalSpace = NetlinkConstants.alignedLengthOf(
|
||||
neighMsg.mHeader.nlmsg_len - kMinConsumed);
|
||||
if (byteBuffer.remaining() < kAdditionalSpace) {
|
||||
byteBuffer.position(byteBuffer.limit());
|
||||
} else {
|
||||
byteBuffer.position(baseOffset + kAdditionalSpace);
|
||||
}
|
||||
|
||||
return neighMsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method to create an RTM_GETNEIGH request message.
|
||||
*/
|
||||
public static byte[] newGetNeighborsRequest(int seqNo) {
|
||||
final int length = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
|
||||
final byte[] bytes = new byte[length];
|
||||
final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
|
||||
byteBuffer.order(ByteOrder.nativeOrder());
|
||||
|
||||
final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
|
||||
nlmsghdr.nlmsg_len = length;
|
||||
nlmsghdr.nlmsg_type = NetlinkConstants.RTM_GETNEIGH;
|
||||
nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
|
||||
nlmsghdr.nlmsg_seq = seqNo;
|
||||
nlmsghdr.pack(byteBuffer);
|
||||
|
||||
final StructNdMsg ndmsg = new StructNdMsg();
|
||||
ndmsg.pack(byteBuffer);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method to create an RTM_NEWNEIGH message, to modify
|
||||
* the kernel's state information for a specific neighbor.
|
||||
*/
|
||||
public static byte[] newNewNeighborMessage(
|
||||
int seqNo, InetAddress ip, short nudState, int ifIndex, byte[] llAddr) {
|
||||
final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
|
||||
nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWNEIGH;
|
||||
nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE;
|
||||
nlmsghdr.nlmsg_seq = seqNo;
|
||||
|
||||
final RtNetlinkNeighborMessage msg = new RtNetlinkNeighborMessage(nlmsghdr);
|
||||
msg.mNdmsg = new StructNdMsg();
|
||||
msg.mNdmsg.ndm_family =
|
||||
(byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET);
|
||||
msg.mNdmsg.ndm_ifindex = ifIndex;
|
||||
msg.mNdmsg.ndm_state = nudState;
|
||||
msg.mDestination = ip;
|
||||
msg.mLinkLayerAddr = llAddr; // might be null
|
||||
|
||||
final byte[] bytes = new byte[msg.getRequiredSpace()];
|
||||
nlmsghdr.nlmsg_len = bytes.length;
|
||||
final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
|
||||
byteBuffer.order(ByteOrder.nativeOrder());
|
||||
msg.pack(byteBuffer);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private StructNdMsg mNdmsg;
|
||||
private InetAddress mDestination;
|
||||
private byte[] mLinkLayerAddr;
|
||||
private int mNumProbes;
|
||||
private StructNdaCacheInfo mCacheInfo;
|
||||
|
||||
private RtNetlinkNeighborMessage(StructNlMsgHdr header) {
|
||||
super(header);
|
||||
mNdmsg = null;
|
||||
mDestination = null;
|
||||
mLinkLayerAddr = null;
|
||||
mNumProbes = 0;
|
||||
mCacheInfo = null;
|
||||
}
|
||||
|
||||
public StructNdMsg getNdHeader() {
|
||||
return mNdmsg;
|
||||
}
|
||||
|
||||
public InetAddress getDestination() {
|
||||
return mDestination;
|
||||
}
|
||||
|
||||
public byte[] getLinkLayerAddress() {
|
||||
return mLinkLayerAddr;
|
||||
}
|
||||
|
||||
public int getProbes() {
|
||||
return mNumProbes;
|
||||
}
|
||||
|
||||
public StructNdaCacheInfo getCacheInfo() {
|
||||
return mCacheInfo;
|
||||
}
|
||||
|
||||
public int getRequiredSpace() {
|
||||
int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
|
||||
if (mDestination != null) {
|
||||
spaceRequired += NetlinkConstants.alignedLengthOf(
|
||||
StructNlAttr.NLA_HEADERLEN + mDestination.getAddress().length);
|
||||
}
|
||||
if (mLinkLayerAddr != null) {
|
||||
spaceRequired += NetlinkConstants.alignedLengthOf(
|
||||
StructNlAttr.NLA_HEADERLEN + mLinkLayerAddr.length);
|
||||
}
|
||||
// Currently we don't write messages with NDA_PROBES nor NDA_CACHEINFO
|
||||
// attributes appended. Fix later, if necessary.
|
||||
return spaceRequired;
|
||||
}
|
||||
|
||||
private static void packNlAttr(short nlType, byte[] nlValue, ByteBuffer byteBuffer) {
|
||||
final StructNlAttr nlAttr = new StructNlAttr();
|
||||
nlAttr.nla_type = nlType;
|
||||
nlAttr.nla_value = nlValue;
|
||||
nlAttr.nla_len = (short) (StructNlAttr.NLA_HEADERLEN + nlAttr.nla_value.length);
|
||||
nlAttr.pack(byteBuffer);
|
||||
}
|
||||
|
||||
public void pack(ByteBuffer byteBuffer) {
|
||||
getHeader().pack(byteBuffer) ;
|
||||
mNdmsg.pack(byteBuffer);
|
||||
|
||||
if (mDestination != null) {
|
||||
packNlAttr(NDA_DST, mDestination.getAddress(), byteBuffer);
|
||||
}
|
||||
if (mLinkLayerAddr != null) {
|
||||
packNlAttr(NDA_LLADDR, mLinkLayerAddr, byteBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress();
|
||||
return "RtNetlinkNeighborMessage{ "
|
||||
+ "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, "
|
||||
+ "ndmsg{" + (mNdmsg == null ? "" : mNdmsg.toString()) + "}, "
|
||||
+ "destination{" + ipLiteral + "} "
|
||||
+ "linklayeraddr{" + NetlinkConstants.hexify(mLinkLayerAddr) + "} "
|
||||
+ "probes{" + mNumProbes + "} "
|
||||
+ "cacheinfo{" + (mCacheInfo == null ? "" : mCacheInfo.toString()) + "} "
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* 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 android.net.netlink;
|
||||
|
||||
import static java.nio.ByteOrder.BIG_ENDIAN;
|
||||
import static android.system.OsConstants.AF_INET;
|
||||
import static android.system.OsConstants.AF_INET6;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* struct inet_diag_msg
|
||||
*
|
||||
* see <linux_src>/include/uapi/linux/inet_diag.h
|
||||
*
|
||||
* struct inet_diag_msg {
|
||||
* __u8 idiag_family;
|
||||
* __u8 idiag_state;
|
||||
* __u8 idiag_timer;
|
||||
* __u8 idiag_retrans;
|
||||
* struct inet_diag_sockid id;
|
||||
* __u32 idiag_expires;
|
||||
* __u32 idiag_rqueue;
|
||||
* __u32 idiag_wqueue;
|
||||
* __u32 idiag_uid;
|
||||
* __u32 idiag_inode;
|
||||
* };
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class StructInetDiagMsg {
|
||||
public static final int STRUCT_SIZE = 4 + StructInetDiagSockId.STRUCT_SIZE + 20;
|
||||
private static final int IDIAG_UID_OFFSET = StructNlMsgHdr.STRUCT_SIZE + 4 +
|
||||
StructInetDiagSockId.STRUCT_SIZE + 12;
|
||||
public int idiag_uid;
|
||||
|
||||
public static StructInetDiagMsg parse(ByteBuffer byteBuffer) {
|
||||
StructInetDiagMsg struct = new StructInetDiagMsg();
|
||||
struct.idiag_uid = byteBuffer.getInt(IDIAG_UID_OFFSET);
|
||||
return struct;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StructInetDiagMsg{ "
|
||||
+ "idiag_uid{" + idiag_uid + "}, "
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* 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 android.net.netlink;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* struct inet_diag_req_v2
|
||||
*
|
||||
* see <linux_src>/include/uapi/linux/inet_diag.h
|
||||
*
|
||||
* struct inet_diag_req_v2 {
|
||||
* __u8 sdiag_family;
|
||||
* __u8 sdiag_protocol;
|
||||
* __u8 idiag_ext;
|
||||
* __u8 pad;
|
||||
* __u32 idiag_states;
|
||||
* struct inet_diag_sockid id;
|
||||
* };
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class StructInetDiagReqV2 {
|
||||
public static final int STRUCT_SIZE = 8 + StructInetDiagSockId.STRUCT_SIZE;
|
||||
|
||||
private final byte mSdiagFamily;
|
||||
private final byte mSdiagProtocol;
|
||||
private final byte mIdiagExt;
|
||||
private final byte mPad;
|
||||
private final StructInetDiagSockId mId;
|
||||
private final int mState;
|
||||
public static final int INET_DIAG_REQ_V2_ALL_STATES = (int) 0xffffffff;
|
||||
|
||||
public StructInetDiagReqV2(int protocol, InetSocketAddress local, InetSocketAddress remote,
|
||||
int family) {
|
||||
this(protocol, local, remote, family, 0 /* pad */, 0 /* extension */,
|
||||
INET_DIAG_REQ_V2_ALL_STATES);
|
||||
}
|
||||
|
||||
public StructInetDiagReqV2(int protocol, @Nullable InetSocketAddress local,
|
||||
@Nullable InetSocketAddress remote, int family, int pad, int extension, int state)
|
||||
throws NullPointerException {
|
||||
mSdiagFamily = (byte) family;
|
||||
mSdiagProtocol = (byte) protocol;
|
||||
// Request for all sockets if no specific socket is requested. Specify the local and remote
|
||||
// socket address information for target request socket.
|
||||
if ((local == null) != (remote == null)) {
|
||||
throw new NullPointerException("Local and remote must be both null or both non-null");
|
||||
}
|
||||
mId = ((local != null && remote != null) ? new StructInetDiagSockId(local, remote) : null);
|
||||
mPad = (byte) pad;
|
||||
mIdiagExt = (byte) extension;
|
||||
mState = state;
|
||||
}
|
||||
|
||||
public void pack(ByteBuffer byteBuffer) {
|
||||
// The ByteOrder must have already been set by the caller.
|
||||
byteBuffer.put((byte) mSdiagFamily);
|
||||
byteBuffer.put((byte) mSdiagProtocol);
|
||||
byteBuffer.put((byte) mIdiagExt);
|
||||
byteBuffer.put((byte) mPad);
|
||||
byteBuffer.putInt(mState);
|
||||
if (mId != null) mId.pack(byteBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final String familyStr = NetlinkConstants.stringForAddressFamily(mSdiagFamily);
|
||||
final String protocolStr = NetlinkConstants.stringForAddressFamily(mSdiagProtocol);
|
||||
|
||||
return "StructInetDiagReqV2{ "
|
||||
+ "sdiag_family{" + familyStr + "}, "
|
||||
+ "sdiag_protocol{" + protocolStr + "}, "
|
||||
+ "idiag_ext{" + mIdiagExt + ")}, "
|
||||
+ "pad{" + mPad + "}, "
|
||||
+ "idiag_states{" + Integer.toHexString(mState) + "}, "
|
||||
+ ((mId != null) ? mId.toString() : "inet_diag_sockid=null")
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* 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 android.net.netlink;
|
||||
|
||||
import static java.nio.ByteOrder.BIG_ENDIAN;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* struct inet_diag_req_v2
|
||||
*
|
||||
* see <linux_src>/include/uapi/linux/inet_diag.h
|
||||
*
|
||||
* struct inet_diag_sockid {
|
||||
* __be16 idiag_sport;
|
||||
* __be16 idiag_dport;
|
||||
* __be32 idiag_src[4];
|
||||
* __be32 idiag_dst[4];
|
||||
* __u32 idiag_if;
|
||||
* __u32 idiag_cookie[2];
|
||||
* #define INET_DIAG_NOCOOKIE (~0U)
|
||||
* };
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class StructInetDiagSockId {
|
||||
public static final int STRUCT_SIZE = 48;
|
||||
|
||||
private final InetSocketAddress mLocSocketAddress;
|
||||
private final InetSocketAddress mRemSocketAddress;
|
||||
private final byte[] INET_DIAG_NOCOOKIE = new byte[]{
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
|
||||
private final byte[] IPV4_PADDING = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
public StructInetDiagSockId(InetSocketAddress loc, InetSocketAddress rem) {
|
||||
mLocSocketAddress = loc;
|
||||
mRemSocketAddress = rem;
|
||||
}
|
||||
|
||||
public void pack(ByteBuffer byteBuffer) {
|
||||
byteBuffer.order(BIG_ENDIAN);
|
||||
byteBuffer.putShort((short) mLocSocketAddress.getPort());
|
||||
byteBuffer.putShort((short) mRemSocketAddress.getPort());
|
||||
byteBuffer.put(mLocSocketAddress.getAddress().getAddress());
|
||||
if (mLocSocketAddress.getAddress() instanceof Inet4Address) {
|
||||
byteBuffer.put(IPV4_PADDING);
|
||||
}
|
||||
byteBuffer.put(mRemSocketAddress.getAddress().getAddress());
|
||||
if (mRemSocketAddress.getAddress() instanceof Inet4Address) {
|
||||
byteBuffer.put(IPV4_PADDING);
|
||||
}
|
||||
byteBuffer.order(ByteOrder.nativeOrder());
|
||||
byteBuffer.putInt(0);
|
||||
byteBuffer.put(INET_DIAG_NOCOOKIE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StructInetDiagSockId{ "
|
||||
+ "idiag_sport{" + mLocSocketAddress.getPort() + "}, "
|
||||
+ "idiag_dport{" + mRemSocketAddress.getPort() + "}, "
|
||||
+ "idiag_src{" + mLocSocketAddress.getAddress().getHostAddress() + "}, "
|
||||
+ "idiag_dst{" + mRemSocketAddress.getAddress().getHostAddress() + "}, "
|
||||
+ "idiag_if{" + 0 + "} "
|
||||
+ "idiag_cookie{INET_DIAG_NOCOOKIE}"
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 android.net.netlink;
|
||||
|
||||
import android.net.netlink.NetlinkConstants;
|
||||
import android.system.OsConstants;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
||||
/**
|
||||
* struct ndmsg
|
||||
*
|
||||
* see: <linux_src>/include/uapi/linux/neighbour.h
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class StructNdMsg {
|
||||
// Already aligned.
|
||||
public static final int STRUCT_SIZE = 12;
|
||||
|
||||
// Neighbor Cache Entry States
|
||||
public static final short NUD_NONE = 0x00;
|
||||
public static final short NUD_INCOMPLETE = 0x01;
|
||||
public static final short NUD_REACHABLE = 0x02;
|
||||
public static final short NUD_STALE = 0x04;
|
||||
public static final short NUD_DELAY = 0x08;
|
||||
public static final short NUD_PROBE = 0x10;
|
||||
public static final short NUD_FAILED = 0x20;
|
||||
public static final short NUD_NOARP = 0x40;
|
||||
public static final short NUD_PERMANENT = 0x80;
|
||||
|
||||
public static String stringForNudState(short nudState) {
|
||||
switch (nudState) {
|
||||
case NUD_NONE: return "NUD_NONE";
|
||||
case NUD_INCOMPLETE: return "NUD_INCOMPLETE";
|
||||
case NUD_REACHABLE: return "NUD_REACHABLE";
|
||||
case NUD_STALE: return "NUD_STALE";
|
||||
case NUD_DELAY: return "NUD_DELAY";
|
||||
case NUD_PROBE: return "NUD_PROBE";
|
||||
case NUD_FAILED: return "NUD_FAILED";
|
||||
case NUD_NOARP: return "NUD_NOARP";
|
||||
case NUD_PERMANENT: return "NUD_PERMANENT";
|
||||
default:
|
||||
return "unknown NUD state: " + String.valueOf(nudState);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isNudStateConnected(short nudState) {
|
||||
return ((nudState & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE)) != 0);
|
||||
}
|
||||
|
||||
public static boolean isNudStateValid(short nudState) {
|
||||
return (isNudStateConnected(nudState) ||
|
||||
((nudState & (NUD_PROBE|NUD_STALE|NUD_DELAY)) != 0));
|
||||
}
|
||||
|
||||
// Neighbor Cache Entry Flags
|
||||
public static byte NTF_USE = (byte) 0x01;
|
||||
public static byte NTF_SELF = (byte) 0x02;
|
||||
public static byte NTF_MASTER = (byte) 0x04;
|
||||
public static byte NTF_PROXY = (byte) 0x08;
|
||||
public static byte NTF_ROUTER = (byte) 0x80;
|
||||
|
||||
public static String stringForNudFlags(byte flags) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
if ((flags & NTF_USE) != 0) {
|
||||
sb.append("NTF_USE");
|
||||
}
|
||||
if ((flags & NTF_SELF) != 0) {
|
||||
if (sb.length() > 0) { sb.append("|"); }
|
||||
sb.append("NTF_SELF");
|
||||
}
|
||||
if ((flags & NTF_MASTER) != 0) {
|
||||
if (sb.length() > 0) { sb.append("|"); }
|
||||
sb.append("NTF_MASTER");
|
||||
}
|
||||
if ((flags & NTF_PROXY) != 0) {
|
||||
if (sb.length() > 0) { sb.append("|");
|
||||
}
|
||||
sb.append("NTF_PROXY"); }
|
||||
if ((flags & NTF_ROUTER) != 0) {
|
||||
if (sb.length() > 0) { sb.append("|"); }
|
||||
sb.append("NTF_ROUTER");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
|
||||
return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
|
||||
}
|
||||
|
||||
public static StructNdMsg parse(ByteBuffer byteBuffer) {
|
||||
if (!hasAvailableSpace(byteBuffer)) { return null; }
|
||||
|
||||
// The ByteOrder must have already been set by the caller. In most
|
||||
// cases ByteOrder.nativeOrder() is correct, with the possible
|
||||
// exception of usage within unittests.
|
||||
final StructNdMsg struct = new StructNdMsg();
|
||||
struct.ndm_family = byteBuffer.get();
|
||||
final byte pad1 = byteBuffer.get();
|
||||
final short pad2 = byteBuffer.getShort();
|
||||
struct.ndm_ifindex = byteBuffer.getInt();
|
||||
struct.ndm_state = byteBuffer.getShort();
|
||||
struct.ndm_flags = byteBuffer.get();
|
||||
struct.ndm_type = byteBuffer.get();
|
||||
return struct;
|
||||
}
|
||||
|
||||
public byte ndm_family;
|
||||
public int ndm_ifindex;
|
||||
public short ndm_state;
|
||||
public byte ndm_flags;
|
||||
public byte ndm_type;
|
||||
|
||||
public StructNdMsg() {
|
||||
ndm_family = (byte) OsConstants.AF_UNSPEC;
|
||||
}
|
||||
|
||||
public void pack(ByteBuffer byteBuffer) {
|
||||
// The ByteOrder must have already been set by the caller. In most
|
||||
// cases ByteOrder.nativeOrder() is correct, with the exception
|
||||
// of usage within unittests.
|
||||
byteBuffer.put(ndm_family);
|
||||
byteBuffer.put((byte) 0); // pad1
|
||||
byteBuffer.putShort((short) 0); // pad2
|
||||
byteBuffer.putInt(ndm_ifindex);
|
||||
byteBuffer.putShort(ndm_state);
|
||||
byteBuffer.put(ndm_flags);
|
||||
byteBuffer.put(ndm_type);
|
||||
}
|
||||
|
||||
public boolean nudConnected() {
|
||||
return isNudStateConnected(ndm_state);
|
||||
}
|
||||
|
||||
public boolean nudValid() {
|
||||
return isNudStateValid(ndm_state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final String stateStr = "" + ndm_state + " (" + stringForNudState(ndm_state) + ")";
|
||||
final String flagsStr = "" + ndm_flags + " (" + stringForNudFlags(ndm_flags) + ")";
|
||||
return "StructNdMsg{ "
|
||||
+ "family{" + NetlinkConstants.stringForAddressFamily((int) ndm_family) + "}, "
|
||||
+ "ifindex{" + ndm_ifindex + "}, "
|
||||
+ "state{" + stateStr + "}, "
|
||||
+ "flags{" + flagsStr + "}, "
|
||||
+ "type{" + ndm_type + "} "
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 android.net.netlink;
|
||||
|
||||
import android.system.Os;
|
||||
import android.system.OsConstants;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
||||
/**
|
||||
* struct nda_cacheinfo
|
||||
*
|
||||
* see: <linux_src>/include/uapi/linux/neighbour.h
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class StructNdaCacheInfo {
|
||||
// Already aligned.
|
||||
public static final int STRUCT_SIZE = 16;
|
||||
|
||||
private static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
|
||||
return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
|
||||
}
|
||||
|
||||
public static StructNdaCacheInfo parse(ByteBuffer byteBuffer) {
|
||||
if (!hasAvailableSpace(byteBuffer)) { return null; }
|
||||
|
||||
// The ByteOrder must have already been set by the caller. In most
|
||||
// cases ByteOrder.nativeOrder() is correct, with the possible
|
||||
// exception of usage within unittests.
|
||||
final StructNdaCacheInfo struct = new StructNdaCacheInfo();
|
||||
struct.ndm_used = byteBuffer.getInt();
|
||||
struct.ndm_confirmed = byteBuffer.getInt();
|
||||
struct.ndm_updated = byteBuffer.getInt();
|
||||
struct.ndm_refcnt = byteBuffer.getInt();
|
||||
return struct;
|
||||
}
|
||||
|
||||
// TODO: investigate whether this can change during device runtime and
|
||||
// decide what (if anything) should be done about that.
|
||||
private static final long CLOCK_TICKS_PER_SECOND = Os.sysconf(OsConstants._SC_CLK_TCK);
|
||||
|
||||
private static long ticksToMilliSeconds(int intClockTicks) {
|
||||
final long longClockTicks = (long) intClockTicks & 0xffffffff;
|
||||
return (longClockTicks * 1000) / CLOCK_TICKS_PER_SECOND;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explanatory notes, for reference.
|
||||
*
|
||||
* Before being returned to user space, the neighbor entry times are
|
||||
* converted to clock_t's like so:
|
||||
*
|
||||
* ndm_used = jiffies_to_clock_t(now - neigh->used);
|
||||
* ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
|
||||
* ndm_updated = jiffies_to_clock_t(now - neigh->updated);
|
||||
*
|
||||
* meaning that these values are expressed as "clock ticks ago". To
|
||||
* convert these clock ticks to seconds divide by sysconf(_SC_CLK_TCK).
|
||||
* When _SC_CLK_TCK is 100, for example, the ndm_* times are expressed
|
||||
* in centiseconds.
|
||||
*
|
||||
* These values are unsigned, but fortunately being expressed as "some
|
||||
* clock ticks ago", these values are typically very small (and
|
||||
* 2^31 centiseconds = 248 days).
|
||||
*
|
||||
* By observation, it appears that:
|
||||
* ndm_used: the last time ARP/ND took place for this neighbor
|
||||
* ndm_confirmed: the last time ARP/ND succeeded for this neighbor OR
|
||||
* higher layer confirmation (TCP or MSG_CONFIRM)
|
||||
* was received
|
||||
* ndm_updated: the time when the current NUD state was entered
|
||||
*/
|
||||
public int ndm_used;
|
||||
public int ndm_confirmed;
|
||||
public int ndm_updated;
|
||||
public int ndm_refcnt;
|
||||
|
||||
public StructNdaCacheInfo() {}
|
||||
|
||||
public long lastUsed() {
|
||||
return ticksToMilliSeconds(ndm_used);
|
||||
}
|
||||
|
||||
public long lastConfirmed() {
|
||||
return ticksToMilliSeconds(ndm_confirmed);
|
||||
}
|
||||
|
||||
public long lastUpdated() {
|
||||
return ticksToMilliSeconds(ndm_updated);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NdaCacheInfo{ "
|
||||
+ "ndm_used{" + lastUsed() + "}, "
|
||||
+ "ndm_confirmed{" + lastConfirmed() + "}, "
|
||||
+ "ndm_updated{" + lastUpdated() + "}, "
|
||||
+ "ndm_refcnt{" + ndm_refcnt + "} "
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.net.netlink;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
||||
/**
|
||||
* struct nfgenmsg
|
||||
*
|
||||
* see <linux_src>/include/uapi/linux/netfilter/nfnetlink.h
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class StructNfGenMsg {
|
||||
public static final int STRUCT_SIZE = 2 + Short.BYTES;
|
||||
|
||||
public static final int NFNETLINK_V0 = 0;
|
||||
|
||||
final public byte nfgen_family;
|
||||
final public byte version;
|
||||
final public short res_id; // N.B.: this is big endian in the kernel
|
||||
|
||||
public StructNfGenMsg(byte family) {
|
||||
nfgen_family = family;
|
||||
version = (byte) NFNETLINK_V0;
|
||||
res_id = (short) 0;
|
||||
}
|
||||
|
||||
public void pack(ByteBuffer byteBuffer) {
|
||||
byteBuffer.put(nfgen_family);
|
||||
byteBuffer.put(version);
|
||||
byteBuffer.putShort(res_id);
|
||||
}
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 android.net.netlink;
|
||||
|
||||
import android.net.netlink.NetlinkConstants;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
||||
/**
|
||||
* struct nlattr
|
||||
*
|
||||
* see: <linux_src>/include/uapi/linux/netlink.h
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class StructNlAttr {
|
||||
// Already aligned.
|
||||
public static final int NLA_HEADERLEN = 4;
|
||||
public static final int NLA_F_NESTED = (1 << 15);
|
||||
|
||||
public static short makeNestedType(short type) {
|
||||
return (short) (type | NLA_F_NESTED);
|
||||
}
|
||||
|
||||
// Return a (length, type) object only, without consuming any bytes in
|
||||
// |byteBuffer| and without copying or interpreting any value bytes.
|
||||
// This is used for scanning over a packed set of struct nlattr's,
|
||||
// looking for instances of a particular type.
|
||||
public static StructNlAttr peek(ByteBuffer byteBuffer) {
|
||||
if (byteBuffer == null || byteBuffer.remaining() < NLA_HEADERLEN) {
|
||||
return null;
|
||||
}
|
||||
final int baseOffset = byteBuffer.position();
|
||||
|
||||
// Assume the byte order of the buffer is the expected byte order of the value.
|
||||
final StructNlAttr struct = new StructNlAttr(byteBuffer.order());
|
||||
// The byte order of nla_len and nla_type is always native.
|
||||
final ByteOrder originalOrder = byteBuffer.order();
|
||||
byteBuffer.order(ByteOrder.nativeOrder());
|
||||
try {
|
||||
struct.nla_len = byteBuffer.getShort();
|
||||
struct.nla_type = byteBuffer.getShort();
|
||||
} finally {
|
||||
byteBuffer.order(originalOrder);
|
||||
}
|
||||
|
||||
byteBuffer.position(baseOffset);
|
||||
if (struct.nla_len < NLA_HEADERLEN) {
|
||||
// Malformed.
|
||||
return null;
|
||||
}
|
||||
return struct;
|
||||
}
|
||||
|
||||
public static StructNlAttr parse(ByteBuffer byteBuffer) {
|
||||
final StructNlAttr struct = peek(byteBuffer);
|
||||
if (struct == null || byteBuffer.remaining() < struct.getAlignedLength()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int baseOffset = byteBuffer.position();
|
||||
byteBuffer.position(baseOffset + NLA_HEADERLEN);
|
||||
|
||||
int valueLen = ((int) struct.nla_len) & 0xffff;
|
||||
valueLen -= NLA_HEADERLEN;
|
||||
if (valueLen > 0) {
|
||||
struct.nla_value = new byte[valueLen];
|
||||
byteBuffer.get(struct.nla_value, 0, valueLen);
|
||||
byteBuffer.position(baseOffset + struct.getAlignedLength());
|
||||
}
|
||||
return struct;
|
||||
}
|
||||
|
||||
public short nla_len = (short) NLA_HEADERLEN;
|
||||
public short nla_type;
|
||||
public byte[] nla_value;
|
||||
|
||||
// The byte order used to read/write the value member. Netlink length and
|
||||
// type members are always read/written in native order.
|
||||
private ByteOrder mByteOrder = ByteOrder.nativeOrder();
|
||||
|
||||
public StructNlAttr() {}
|
||||
|
||||
public StructNlAttr(ByteOrder byteOrder) {
|
||||
mByteOrder = byteOrder;
|
||||
}
|
||||
|
||||
public StructNlAttr(short type, byte value) {
|
||||
nla_type = type;
|
||||
setValue(new byte[1]);
|
||||
nla_value[0] = value;
|
||||
}
|
||||
|
||||
public StructNlAttr(short type, short value) {
|
||||
this(type, value, ByteOrder.nativeOrder());
|
||||
}
|
||||
|
||||
public StructNlAttr(short type, short value, ByteOrder order) {
|
||||
this(order);
|
||||
nla_type = type;
|
||||
setValue(new byte[Short.BYTES]);
|
||||
getValueAsByteBuffer().putShort(value);
|
||||
}
|
||||
|
||||
public StructNlAttr(short type, int value) {
|
||||
this(type, value, ByteOrder.nativeOrder());
|
||||
}
|
||||
|
||||
public StructNlAttr(short type, int value, ByteOrder order) {
|
||||
this(order);
|
||||
nla_type = type;
|
||||
setValue(new byte[Integer.BYTES]);
|
||||
getValueAsByteBuffer().putInt(value);
|
||||
}
|
||||
|
||||
public StructNlAttr(short type, InetAddress ip) {
|
||||
nla_type = type;
|
||||
setValue(ip.getAddress());
|
||||
}
|
||||
|
||||
public StructNlAttr(short type, StructNlAttr... nested) {
|
||||
this();
|
||||
nla_type = makeNestedType(type);
|
||||
|
||||
int payloadLength = 0;
|
||||
for (StructNlAttr nla : nested) payloadLength += nla.getAlignedLength();
|
||||
setValue(new byte[payloadLength]);
|
||||
|
||||
final ByteBuffer buf = getValueAsByteBuffer();
|
||||
for (StructNlAttr nla : nested) {
|
||||
nla.pack(buf);
|
||||
}
|
||||
}
|
||||
|
||||
public int getAlignedLength() {
|
||||
return NetlinkConstants.alignedLengthOf(nla_len);
|
||||
}
|
||||
|
||||
public ByteBuffer getValueAsByteBuffer() {
|
||||
if (nla_value == null) { return null; }
|
||||
final ByteBuffer byteBuffer = ByteBuffer.wrap(nla_value);
|
||||
byteBuffer.order(mByteOrder);
|
||||
return byteBuffer;
|
||||
}
|
||||
|
||||
public int getValueAsInt(int defaultValue) {
|
||||
final ByteBuffer byteBuffer = getValueAsByteBuffer();
|
||||
if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) {
|
||||
return defaultValue;
|
||||
}
|
||||
return getValueAsByteBuffer().getInt();
|
||||
}
|
||||
|
||||
public InetAddress getValueAsInetAddress() {
|
||||
if (nla_value == null) { return null; }
|
||||
|
||||
try {
|
||||
return InetAddress.getByAddress(nla_value);
|
||||
} catch (UnknownHostException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void pack(ByteBuffer byteBuffer) {
|
||||
final ByteOrder originalOrder = byteBuffer.order();
|
||||
final int originalPosition = byteBuffer.position();
|
||||
|
||||
byteBuffer.order(ByteOrder.nativeOrder());
|
||||
try {
|
||||
byteBuffer.putShort(nla_len);
|
||||
byteBuffer.putShort(nla_type);
|
||||
if (nla_value != null) byteBuffer.put(nla_value);
|
||||
} finally {
|
||||
byteBuffer.order(originalOrder);
|
||||
}
|
||||
byteBuffer.position(originalPosition + getAlignedLength());
|
||||
}
|
||||
|
||||
private void setValue(byte[] value) {
|
||||
nla_value = value;
|
||||
nla_len = (short) (NLA_HEADERLEN + ((nla_value != null) ? nla_value.length : 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StructNlAttr{ "
|
||||
+ "nla_len{" + nla_len + "}, "
|
||||
+ "nla_type{" + nla_type + "}, "
|
||||
+ "nla_value{" + NetlinkConstants.hexify(nla_value) + "}, "
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 android.net.netlink;
|
||||
|
||||
import android.net.netlink.NetlinkConstants;
|
||||
import android.net.netlink.StructNlMsgHdr;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
||||
/**
|
||||
* struct nlmsgerr
|
||||
*
|
||||
* see <linux_src>/include/uapi/linux/netlink.h
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class StructNlMsgErr {
|
||||
public static final int STRUCT_SIZE = Integer.BYTES + StructNlMsgHdr.STRUCT_SIZE;
|
||||
|
||||
public static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
|
||||
return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
|
||||
}
|
||||
|
||||
public static StructNlMsgErr parse(ByteBuffer byteBuffer) {
|
||||
if (!hasAvailableSpace(byteBuffer)) { return null; }
|
||||
|
||||
// The ByteOrder must have already been set by the caller. In most
|
||||
// cases ByteOrder.nativeOrder() is correct, with the exception
|
||||
// of usage within unittests.
|
||||
final StructNlMsgErr struct = new StructNlMsgErr();
|
||||
struct.error = byteBuffer.getInt();
|
||||
struct.msg = StructNlMsgHdr.parse(byteBuffer);
|
||||
return struct;
|
||||
}
|
||||
|
||||
public int error;
|
||||
public StructNlMsgHdr msg;
|
||||
|
||||
public void pack(ByteBuffer byteBuffer) {
|
||||
// The ByteOrder must have already been set by the caller. In most
|
||||
// cases ByteOrder.nativeOrder() is correct, with the possible
|
||||
// exception of usage within unittests.
|
||||
byteBuffer.putInt(error);
|
||||
if (msg != null) {
|
||||
msg.pack(byteBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StructNlMsgErr{ "
|
||||
+ "error{" + error + "}, "
|
||||
+ "msg{" + (msg == null ? "" : msg.toString()) + "} "
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 android.net.netlink;
|
||||
|
||||
import android.net.netlink.NetlinkConstants;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
||||
/**
|
||||
* struct nlmsghdr
|
||||
*
|
||||
* see <linux_src>/include/uapi/linux/netlink.h
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class StructNlMsgHdr {
|
||||
// Already aligned.
|
||||
public static final int STRUCT_SIZE = 16;
|
||||
|
||||
public static final short NLM_F_REQUEST = 0x0001;
|
||||
public static final short NLM_F_MULTI = 0x0002;
|
||||
public static final short NLM_F_ACK = 0x0004;
|
||||
public static final short NLM_F_ECHO = 0x0008;
|
||||
// Flags for a GET request.
|
||||
public static final short NLM_F_ROOT = 0x0100;
|
||||
public static final short NLM_F_MATCH = 0x0200;
|
||||
public static final short NLM_F_DUMP = NLM_F_ROOT|NLM_F_MATCH;
|
||||
// Flags for a NEW request.
|
||||
public static final short NLM_F_REPLACE = 0x100;
|
||||
public static final short NLM_F_EXCL = 0x200;
|
||||
public static final short NLM_F_CREATE = 0x400;
|
||||
public static final short NLM_F_APPEND = 0x800;
|
||||
|
||||
|
||||
public static String stringForNlMsgFlags(short flags) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
if ((flags & NLM_F_REQUEST) != 0) {
|
||||
sb.append("NLM_F_REQUEST");
|
||||
}
|
||||
if ((flags & NLM_F_MULTI) != 0) {
|
||||
if (sb.length() > 0) { sb.append("|"); }
|
||||
sb.append("NLM_F_MULTI");
|
||||
}
|
||||
if ((flags & NLM_F_ACK) != 0) {
|
||||
if (sb.length() > 0) { sb.append("|"); }
|
||||
sb.append("NLM_F_ACK");
|
||||
}
|
||||
if ((flags & NLM_F_ECHO) != 0) {
|
||||
if (sb.length() > 0) { sb.append("|"); }
|
||||
sb.append("NLM_F_ECHO");
|
||||
}
|
||||
if ((flags & NLM_F_ROOT) != 0) {
|
||||
if (sb.length() > 0) { sb.append("|"); }
|
||||
sb.append("NLM_F_ROOT");
|
||||
}
|
||||
if ((flags & NLM_F_MATCH) != 0) {
|
||||
if (sb.length() > 0) { sb.append("|"); }
|
||||
sb.append("NLM_F_MATCH");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
|
||||
return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
|
||||
}
|
||||
|
||||
public static StructNlMsgHdr parse(ByteBuffer byteBuffer) {
|
||||
if (!hasAvailableSpace(byteBuffer)) { return null; }
|
||||
|
||||
// The ByteOrder must have already been set by the caller. In most
|
||||
// cases ByteOrder.nativeOrder() is correct, with the exception
|
||||
// of usage within unittests.
|
||||
final StructNlMsgHdr struct = new StructNlMsgHdr();
|
||||
struct.nlmsg_len = byteBuffer.getInt();
|
||||
struct.nlmsg_type = byteBuffer.getShort();
|
||||
struct.nlmsg_flags = byteBuffer.getShort();
|
||||
struct.nlmsg_seq = byteBuffer.getInt();
|
||||
struct.nlmsg_pid = byteBuffer.getInt();
|
||||
|
||||
if (struct.nlmsg_len < STRUCT_SIZE) {
|
||||
// Malformed.
|
||||
return null;
|
||||
}
|
||||
return struct;
|
||||
}
|
||||
|
||||
public int nlmsg_len;
|
||||
public short nlmsg_type;
|
||||
public short nlmsg_flags;
|
||||
public int nlmsg_seq;
|
||||
public int nlmsg_pid;
|
||||
|
||||
public StructNlMsgHdr() {
|
||||
nlmsg_len = 0;
|
||||
nlmsg_type = 0;
|
||||
nlmsg_flags = 0;
|
||||
nlmsg_seq = 0;
|
||||
nlmsg_pid = 0;
|
||||
}
|
||||
|
||||
public void pack(ByteBuffer byteBuffer) {
|
||||
// The ByteOrder must have already been set by the caller. In most
|
||||
// cases ByteOrder.nativeOrder() is correct, with the possible
|
||||
// exception of usage within unittests.
|
||||
byteBuffer.putInt(nlmsg_len);
|
||||
byteBuffer.putShort(nlmsg_type);
|
||||
byteBuffer.putShort(nlmsg_flags);
|
||||
byteBuffer.putInt(nlmsg_seq);
|
||||
byteBuffer.putInt(nlmsg_pid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final String typeStr = "" + nlmsg_type
|
||||
+ "(" + NetlinkConstants.stringForNlMsgType(nlmsg_type) + ")";
|
||||
final String flagsStr = "" + nlmsg_flags
|
||||
+ "(" + stringForNlMsgFlags(nlmsg_flags) + ")";
|
||||
return "StructNlMsgHdr{ "
|
||||
+ "nlmsg_len{" + nlmsg_len + "}, "
|
||||
+ "nlmsg_type{" + typeStr + "}, "
|
||||
+ "nlmsg_flags{" + flagsStr + ")}, "
|
||||
+ "nlmsg_seq{" + nlmsg_seq + "}, "
|
||||
+ "nlmsg_pid{" + nlmsg_pid + "} "
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 android.net.shared;
|
||||
|
||||
import static android.net.shared.ParcelableUtil.fromParcelableArray;
|
||||
import static android.net.shared.ParcelableUtil.toParcelableArray;
|
||||
import static android.text.TextUtils.join;
|
||||
|
||||
import android.net.InetAddresses;
|
||||
import android.net.InitialConfigurationParcelable;
|
||||
import android.net.IpPrefix;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.RouteInfo;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/** @hide */
|
||||
public class InitialConfiguration {
|
||||
public final Set<LinkAddress> ipAddresses = new HashSet<>();
|
||||
public final Set<IpPrefix> directlyConnectedRoutes = new HashSet<>();
|
||||
public final Set<InetAddress> dnsServers = new HashSet<>();
|
||||
|
||||
private static final int RFC6177_MIN_PREFIX_LENGTH = 48;
|
||||
private static final int RFC7421_PREFIX_LENGTH = 64;
|
||||
|
||||
public static final InetAddress INET6_ANY = InetAddresses.parseNumericAddress("::");
|
||||
|
||||
/**
|
||||
* Create a InitialConfiguration that is a copy of the specified configuration.
|
||||
*/
|
||||
public static InitialConfiguration copy(InitialConfiguration config) {
|
||||
if (config == null) {
|
||||
return null;
|
||||
}
|
||||
InitialConfiguration configCopy = new InitialConfiguration();
|
||||
configCopy.ipAddresses.addAll(config.ipAddresses);
|
||||
configCopy.directlyConnectedRoutes.addAll(config.directlyConnectedRoutes);
|
||||
configCopy.dnsServers.addAll(config.dnsServers);
|
||||
return configCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
"InitialConfiguration(IPs: {%s}, prefixes: {%s}, DNS: {%s})",
|
||||
join(", ", ipAddresses), join(", ", directlyConnectedRoutes),
|
||||
join(", ", dnsServers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the contents of this IpConfiguration represent a valid configuration.
|
||||
*/
|
||||
public boolean isValid() {
|
||||
if (ipAddresses.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For every IP address, there must be at least one prefix containing that address.
|
||||
for (LinkAddress addr : ipAddresses) {
|
||||
if (!any(directlyConnectedRoutes, (p) -> p.contains(addr.getAddress()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// For every dns server, there must be at least one prefix containing that address.
|
||||
for (InetAddress addr : dnsServers) {
|
||||
if (!any(directlyConnectedRoutes, (p) -> p.contains(addr))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// All IPv6 LinkAddresses have an RFC7421-suitable prefix length
|
||||
// (read: compliant with RFC4291#section2.5.4).
|
||||
if (any(ipAddresses, not(InitialConfiguration::isPrefixLengthCompliant))) {
|
||||
return false;
|
||||
}
|
||||
// If directlyConnectedRoutes contains an IPv6 default route
|
||||
// then ipAddresses MUST contain at least one non-ULA GUA.
|
||||
if (any(directlyConnectedRoutes, InitialConfiguration::isIPv6DefaultRoute)
|
||||
&& all(ipAddresses, not(InitialConfiguration::isIPv6GUA))) {
|
||||
return false;
|
||||
}
|
||||
// The prefix length of routes in directlyConnectedRoutes be within reasonable
|
||||
// bounds for IPv6: /48-/64 just as we’d accept in RIOs.
|
||||
if (any(directlyConnectedRoutes, not(InitialConfiguration::isPrefixLengthCompliant))) {
|
||||
return false;
|
||||
}
|
||||
// There no more than one IPv4 address
|
||||
if (ipAddresses.stream().filter(InitialConfiguration::isIPv4).count() > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the given list of addressess and routes satisfies provisioning for this
|
||||
* InitialConfiguration. LinkAddresses and RouteInfo objects are not compared with equality
|
||||
* because addresses and routes seen by Netlink will contain additional fields like flags,
|
||||
* interfaces, and so on. If this InitialConfiguration has no IP address specified, the
|
||||
* provisioning check always fails.
|
||||
*
|
||||
* If the given list of routes is null, only addresses are taken into considerations.
|
||||
*/
|
||||
public boolean isProvisionedBy(List<LinkAddress> addresses, List<RouteInfo> routes) {
|
||||
if (ipAddresses.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (LinkAddress addr : ipAddresses) {
|
||||
if (!any(addresses, (addrSeen) -> addr.isSameAddressAs(addrSeen))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (routes != null) {
|
||||
for (IpPrefix prefix : directlyConnectedRoutes) {
|
||||
if (!any(routes, (routeSeen) -> isDirectlyConnectedRoute(routeSeen, prefix))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this configuration to a {@link InitialConfigurationParcelable}.
|
||||
*/
|
||||
public InitialConfigurationParcelable toStableParcelable() {
|
||||
final InitialConfigurationParcelable p = new InitialConfigurationParcelable();
|
||||
p.ipAddresses = ipAddresses.toArray(new LinkAddress[0]);
|
||||
p.directlyConnectedRoutes = directlyConnectedRoutes.toArray(new IpPrefix[0]);
|
||||
p.dnsServers = toParcelableArray(
|
||||
dnsServers, IpConfigurationParcelableUtil::parcelAddress, String.class);
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link InitialConfiguration} based on the contents of the specified
|
||||
* {@link InitialConfigurationParcelable}.
|
||||
*/
|
||||
public static InitialConfiguration fromStableParcelable(InitialConfigurationParcelable p) {
|
||||
if (p == null) return null;
|
||||
final InitialConfiguration config = new InitialConfiguration();
|
||||
config.ipAddresses.addAll(Arrays.asList(p.ipAddresses));
|
||||
config.directlyConnectedRoutes.addAll(Arrays.asList(p.directlyConnectedRoutes));
|
||||
config.dnsServers.addAll(
|
||||
fromParcelableArray(p.dnsServers, IpConfigurationParcelableUtil::unparcelAddress));
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof InitialConfiguration)) return false;
|
||||
final InitialConfiguration other = (InitialConfiguration) obj;
|
||||
return ipAddresses.equals(other.ipAddresses)
|
||||
&& directlyConnectedRoutes.equals(other.directlyConnectedRoutes)
|
||||
&& dnsServers.equals(other.dnsServers);
|
||||
}
|
||||
|
||||
private static boolean isDirectlyConnectedRoute(RouteInfo route, IpPrefix prefix) {
|
||||
return !route.hasGateway() && prefix.equals(route.getDestination());
|
||||
}
|
||||
|
||||
private static boolean isPrefixLengthCompliant(LinkAddress addr) {
|
||||
return isIPv4(addr) || isCompliantIPv6PrefixLength(addr.getPrefixLength());
|
||||
}
|
||||
|
||||
private static boolean isPrefixLengthCompliant(IpPrefix prefix) {
|
||||
return isIPv4(prefix) || isCompliantIPv6PrefixLength(prefix.getPrefixLength());
|
||||
}
|
||||
|
||||
private static boolean isCompliantIPv6PrefixLength(int prefixLength) {
|
||||
return (RFC6177_MIN_PREFIX_LENGTH <= prefixLength)
|
||||
&& (prefixLength <= RFC7421_PREFIX_LENGTH);
|
||||
}
|
||||
|
||||
private static boolean isIPv4(IpPrefix prefix) {
|
||||
return prefix.getAddress() instanceof Inet4Address;
|
||||
}
|
||||
|
||||
private static boolean isIPv4(LinkAddress addr) {
|
||||
return addr.getAddress() instanceof Inet4Address;
|
||||
}
|
||||
|
||||
private static boolean isIPv6DefaultRoute(IpPrefix prefix) {
|
||||
return prefix.getAddress().equals(INET6_ANY);
|
||||
}
|
||||
|
||||
private static boolean isIPv6GUA(LinkAddress addr) {
|
||||
return addr.isIpv6() && addr.isGlobalPreferred();
|
||||
}
|
||||
|
||||
// TODO: extract out into CollectionUtils.
|
||||
|
||||
/**
|
||||
* Indicate whether any element of the specified iterable verifies the specified predicate.
|
||||
*/
|
||||
public static <T> boolean any(Iterable<T> coll, Predicate<T> fn) {
|
||||
for (T t : coll) {
|
||||
if (fn.test(t)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate whether all elements of the specified iterable verifies the specified predicate.
|
||||
*/
|
||||
public static <T> boolean all(Iterable<T> coll, Predicate<T> fn) {
|
||||
return !any(coll, not(fn));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a predicate that returns the opposite value of the specified predicate.
|
||||
*/
|
||||
public static <T> Predicate<T> not(Predicate<T> fn) {
|
||||
return (t) -> !fn.test(t);
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 android.net.shared;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.net.DhcpResults;
|
||||
import android.net.DhcpResultsParcelable;
|
||||
import android.net.InetAddresses;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* Collection of utility methods to convert to and from stable AIDL parcelables for IpClient
|
||||
* configuration classes.
|
||||
* @hide
|
||||
*/
|
||||
public final class IpConfigurationParcelableUtil {
|
||||
/**
|
||||
* Convert DhcpResults to a DhcpResultsParcelable.
|
||||
*/
|
||||
public static DhcpResultsParcelable toStableParcelable(@Nullable DhcpResults results) {
|
||||
if (results == null) return null;
|
||||
final DhcpResultsParcelable p = new DhcpResultsParcelable();
|
||||
p.baseConfiguration = results.toStaticIpConfiguration();
|
||||
p.leaseDuration = results.leaseDuration;
|
||||
p.mtu = results.mtu;
|
||||
p.serverAddress = parcelAddress(results.serverAddress);
|
||||
p.vendorInfo = results.vendorInfo;
|
||||
p.serverHostName = results.serverHostName;
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a DhcpResultsParcelable to DhcpResults.
|
||||
*/
|
||||
public static DhcpResults fromStableParcelable(@Nullable DhcpResultsParcelable p) {
|
||||
if (p == null) return null;
|
||||
final DhcpResults results = new DhcpResults(p.baseConfiguration);
|
||||
results.leaseDuration = p.leaseDuration;
|
||||
results.mtu = p.mtu;
|
||||
results.serverAddress = (Inet4Address) unparcelAddress(p.serverAddress);
|
||||
results.vendorInfo = p.vendorInfo;
|
||||
results.serverHostName = p.serverHostName;
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert InetAddress to String.
|
||||
* TODO: have an InetAddressParcelable
|
||||
*/
|
||||
public static String parcelAddress(@Nullable InetAddress addr) {
|
||||
if (addr == null) return null;
|
||||
return addr.getHostAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert String to InetAddress.
|
||||
* TODO: have an InetAddressParcelable
|
||||
*/
|
||||
public static InetAddress unparcelAddress(@Nullable String addr) {
|
||||
if (addr == null) return null;
|
||||
return InetAddresses.parseNumericAddress(addr);
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 android.net.shared;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.ProxyInfo;
|
||||
|
||||
/**
|
||||
* Collection of utility methods to convert to and from stable AIDL parcelables for LinkProperties
|
||||
* and its attributes.
|
||||
* @hide
|
||||
*/
|
||||
public final class LinkPropertiesParcelableUtil {
|
||||
// Temporary methods to facilitate migrating clients away from LinkPropertiesParcelable
|
||||
// TODO: remove the following methods after migrating clients.
|
||||
|
||||
/**
|
||||
* @deprecated conversion to stable parcelable is no longer necessary.
|
||||
*/
|
||||
@Deprecated
|
||||
public static LinkProperties toStableParcelable(@Nullable LinkProperties lp) {
|
||||
return lp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated conversion to stable parcelable is no longer necessary.
|
||||
*/
|
||||
@Deprecated
|
||||
public static ProxyInfo toStableParcelable(@Nullable ProxyInfo info) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* 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 android.net.shared;
|
||||
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
|
||||
|
||||
import android.net.NetworkCapabilities;
|
||||
|
||||
/** @hide */
|
||||
public class NetworkMonitorUtils {
|
||||
|
||||
// Network conditions broadcast constants
|
||||
public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
|
||||
"android.net.conn.NETWORK_CONDITIONS_MEASURED";
|
||||
public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
|
||||
public static final String EXTRA_NETWORK_TYPE = "extra_network_type";
|
||||
public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received";
|
||||
public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal";
|
||||
public static final String EXTRA_CELL_ID = "extra_cellid";
|
||||
public static final String EXTRA_SSID = "extra_ssid";
|
||||
public static final String EXTRA_BSSID = "extra_bssid";
|
||||
/** real time since boot */
|
||||
public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms";
|
||||
public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms";
|
||||
public static final String PERMISSION_ACCESS_NETWORK_CONDITIONS =
|
||||
"android.permission.ACCESS_NETWORK_CONDITIONS";
|
||||
|
||||
/**
|
||||
* Return whether validation is required for private DNS in strict mode.
|
||||
* @param nc Network capabilities of the network to test.
|
||||
*/
|
||||
public static boolean isPrivateDnsValidationRequired(NetworkCapabilities nc) {
|
||||
// TODO: Consider requiring validation for DUN networks.
|
||||
return nc != null
|
||||
&& nc.hasCapability(NET_CAPABILITY_INTERNET)
|
||||
&& nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
|
||||
&& nc.hasCapability(NET_CAPABILITY_TRUSTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether validation is required for a network.
|
||||
* @param nc Network capabilities of the network to test.
|
||||
*/
|
||||
public static boolean isValidationRequired(NetworkCapabilities nc) {
|
||||
// TODO: Consider requiring validation for DUN networks.
|
||||
return isPrivateDnsValidationRequired(nc) && nc.hasCapability(NET_CAPABILITY_NOT_VPN);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 android.net.shared;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Utility methods to help convert to/from stable parcelables.
|
||||
* @hide
|
||||
*/
|
||||
public final class ParcelableUtil {
|
||||
// Below methods could be implemented easily with streams, but streams are frowned upon in
|
||||
// frameworks code.
|
||||
|
||||
/**
|
||||
* Convert a list of BaseType items to an array of ParcelableType items using the specified
|
||||
* converter function.
|
||||
*/
|
||||
public static <ParcelableType, BaseType> ParcelableType[] toParcelableArray(
|
||||
@NonNull Collection<BaseType> base,
|
||||
@NonNull Function<BaseType, ParcelableType> conv,
|
||||
@NonNull Class<ParcelableType> parcelClass) {
|
||||
final ParcelableType[] out = (ParcelableType[]) Array.newInstance(parcelClass, base.size());
|
||||
int i = 0;
|
||||
for (BaseType b : base) {
|
||||
out[i] = conv.apply(b);
|
||||
i++;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an array of ParcelableType items to a list of BaseType items using the specified
|
||||
* converter function.
|
||||
*/
|
||||
public static <ParcelableType, BaseType> ArrayList<BaseType> fromParcelableArray(
|
||||
@NonNull ParcelableType[] parceled, @NonNull Function<ParcelableType, BaseType> conv) {
|
||||
final ArrayList<BaseType> out = new ArrayList<>(parceled.length);
|
||||
for (ParcelableType t : parceled) {
|
||||
out.add(conv.apply(t));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* 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 android.net.shared;
|
||||
|
||||
import static android.net.shared.ParcelableUtil.fromParcelableArray;
|
||||
import static android.net.shared.ParcelableUtil.toParcelableArray;
|
||||
|
||||
import android.net.PrivateDnsConfigParcel;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.Arrays;
|
||||
|
||||
/** @hide */
|
||||
public class PrivateDnsConfig {
|
||||
public final boolean useTls;
|
||||
public final String hostname;
|
||||
public final InetAddress[] ips;
|
||||
|
||||
public PrivateDnsConfig() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public PrivateDnsConfig(boolean useTls) {
|
||||
this.useTls = useTls;
|
||||
this.hostname = "";
|
||||
this.ips = new InetAddress[0];
|
||||
}
|
||||
|
||||
public PrivateDnsConfig(String hostname, InetAddress[] ips) {
|
||||
this.useTls = !TextUtils.isEmpty(hostname);
|
||||
this.hostname = useTls ? hostname : "";
|
||||
this.ips = (ips != null) ? ips : new InetAddress[0];
|
||||
}
|
||||
|
||||
public PrivateDnsConfig(PrivateDnsConfig cfg) {
|
||||
useTls = cfg.useTls;
|
||||
hostname = cfg.hostname;
|
||||
ips = cfg.ips;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this is a strict mode private DNS configuration.
|
||||
*/
|
||||
public boolean inStrictMode() {
|
||||
return useTls && !TextUtils.isEmpty(hostname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return PrivateDnsConfig.class.getSimpleName()
|
||||
+ "{" + useTls + ":" + hostname + "/" + Arrays.toString(ips) + "}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a stable AIDL-compatible parcel from the current instance.
|
||||
*/
|
||||
public PrivateDnsConfigParcel toParcel() {
|
||||
final PrivateDnsConfigParcel parcel = new PrivateDnsConfigParcel();
|
||||
parcel.hostname = hostname;
|
||||
parcel.ips = toParcelableArray(
|
||||
Arrays.asList(ips), IpConfigurationParcelableUtil::parcelAddress, String.class);
|
||||
|
||||
return parcel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a configuration from a stable AIDL-compatible parcel.
|
||||
*/
|
||||
public static PrivateDnsConfig fromParcel(PrivateDnsConfigParcel parcel) {
|
||||
InetAddress[] ips = new InetAddress[parcel.ips.length];
|
||||
ips = fromParcelableArray(parcel.ips, IpConfigurationParcelableUtil::unparcelAddress)
|
||||
.toArray(ips);
|
||||
return new PrivateDnsConfig(parcel.hostname, ips);
|
||||
}
|
||||
}
|
||||
@@ -1,312 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 android.net.shared;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.net.INetd;
|
||||
import android.net.Network;
|
||||
import android.net.ProvisioningConfigurationParcelable;
|
||||
import android.net.StaticIpConfiguration;
|
||||
import android.net.apf.ApfCapabilities;
|
||||
import android.net.ip.IIpClient;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/**
|
||||
* This class encapsulates parameters to be passed to
|
||||
* IpClient#startProvisioning(). A defensive copy is made by IpClient
|
||||
* and the values specified herein are in force until IpClient#stop()
|
||||
* is called.
|
||||
*
|
||||
* Example use:
|
||||
*
|
||||
* final ProvisioningConfiguration config =
|
||||
* new ProvisioningConfiguration.Builder()
|
||||
* .withPreDhcpAction()
|
||||
* .withProvisioningTimeoutMs(36 * 1000)
|
||||
* .build();
|
||||
* mIpClient.startProvisioning(config.toStableParcelable());
|
||||
* ...
|
||||
* mIpClient.stop();
|
||||
*
|
||||
* The specified provisioning configuration will only be active until
|
||||
* IIpClient#stop() is called. Future calls to IIpClient#startProvisioning()
|
||||
* must specify the configuration again.
|
||||
* @hide
|
||||
*/
|
||||
public class ProvisioningConfiguration {
|
||||
// TODO: Delete this default timeout once those callers that care are
|
||||
// fixed to pass in their preferred timeout.
|
||||
//
|
||||
// We pick 36 seconds so we can send DHCP requests at
|
||||
//
|
||||
// t=0, t=2, t=6, t=14, t=30
|
||||
//
|
||||
// allowing for 10% jitter.
|
||||
private static final int DEFAULT_TIMEOUT_MS = 36 * 1000;
|
||||
|
||||
/**
|
||||
* Builder to create a {@link ProvisioningConfiguration}.
|
||||
*/
|
||||
public static class Builder {
|
||||
protected ProvisioningConfiguration mConfig = new ProvisioningConfiguration();
|
||||
|
||||
/**
|
||||
* Specify that the configuration should not enable IPv4. It is enabled by default.
|
||||
*/
|
||||
public Builder withoutIPv4() {
|
||||
mConfig.mEnableIPv4 = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that the configuration should not enable IPv6. It is enabled by default.
|
||||
*/
|
||||
public Builder withoutIPv6() {
|
||||
mConfig.mEnableIPv6 = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that the configuration should not use a MultinetworkPolicyTracker. It is used
|
||||
* by default.
|
||||
*/
|
||||
public Builder withoutMultinetworkPolicyTracker() {
|
||||
mConfig.mUsingMultinetworkPolicyTracker = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that the configuration should not use a IpReachabilityMonitor. It is used by
|
||||
* default.
|
||||
*/
|
||||
public Builder withoutIpReachabilityMonitor() {
|
||||
mConfig.mUsingIpReachabilityMonitor = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identical to {@link #withPreDhcpAction(int)}, using a default timeout.
|
||||
* @see #withPreDhcpAction(int)
|
||||
*/
|
||||
public Builder withPreDhcpAction() {
|
||||
mConfig.mRequestedPreDhcpActionMs = DEFAULT_TIMEOUT_MS;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that {@link IpClientCallbacks#onPreDhcpAction()} should be called. Clients must
|
||||
* call {@link IIpClient#completedPreDhcpAction()} when the callback called. This behavior
|
||||
* is disabled by default.
|
||||
* @param dhcpActionTimeoutMs Timeout for clients to call completedPreDhcpAction().
|
||||
*/
|
||||
public Builder withPreDhcpAction(int dhcpActionTimeoutMs) {
|
||||
mConfig.mRequestedPreDhcpActionMs = dhcpActionTimeoutMs;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the initial provisioning configuration.
|
||||
*/
|
||||
public Builder withInitialConfiguration(InitialConfiguration initialConfig) {
|
||||
mConfig.mInitialConfig = initialConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a static configuration for provisioning.
|
||||
*/
|
||||
public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
|
||||
mConfig.mStaticIpConfig = staticConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify ApfCapabilities.
|
||||
*/
|
||||
public Builder withApfCapabilities(ApfCapabilities apfCapabilities) {
|
||||
mConfig.mApfCapabilities = apfCapabilities;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the timeout to use for provisioning.
|
||||
*/
|
||||
public Builder withProvisioningTimeoutMs(int timeoutMs) {
|
||||
mConfig.mProvisioningTimeoutMs = timeoutMs;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that IPv6 address generation should use a random MAC address.
|
||||
*/
|
||||
public Builder withRandomMacAddress() {
|
||||
mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_EUI64;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that IPv6 address generation should use a stable MAC address.
|
||||
*/
|
||||
public Builder withStableMacAddress() {
|
||||
mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the network to use for provisioning.
|
||||
*/
|
||||
public Builder withNetwork(Network network) {
|
||||
mConfig.mNetwork = network;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the display name that the IpClient should use.
|
||||
*/
|
||||
public Builder withDisplayName(String displayName) {
|
||||
mConfig.mDisplayName = displayName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the configuration using previously specified parameters.
|
||||
*/
|
||||
public ProvisioningConfiguration build() {
|
||||
return new ProvisioningConfiguration(mConfig);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean mEnableIPv4 = true;
|
||||
public boolean mEnableIPv6 = true;
|
||||
public boolean mUsingMultinetworkPolicyTracker = true;
|
||||
public boolean mUsingIpReachabilityMonitor = true;
|
||||
public int mRequestedPreDhcpActionMs;
|
||||
public InitialConfiguration mInitialConfig;
|
||||
public StaticIpConfiguration mStaticIpConfig;
|
||||
public ApfCapabilities mApfCapabilities;
|
||||
public int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS;
|
||||
public int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
|
||||
public Network mNetwork = null;
|
||||
public String mDisplayName = null;
|
||||
|
||||
public ProvisioningConfiguration() {} // used by Builder
|
||||
|
||||
public ProvisioningConfiguration(ProvisioningConfiguration other) {
|
||||
mEnableIPv4 = other.mEnableIPv4;
|
||||
mEnableIPv6 = other.mEnableIPv6;
|
||||
mUsingMultinetworkPolicyTracker = other.mUsingMultinetworkPolicyTracker;
|
||||
mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
|
||||
mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs;
|
||||
mInitialConfig = InitialConfiguration.copy(other.mInitialConfig);
|
||||
mStaticIpConfig = other.mStaticIpConfig == null
|
||||
? null
|
||||
: new StaticIpConfiguration(other.mStaticIpConfig);
|
||||
mApfCapabilities = other.mApfCapabilities;
|
||||
mProvisioningTimeoutMs = other.mProvisioningTimeoutMs;
|
||||
mIPv6AddrGenMode = other.mIPv6AddrGenMode;
|
||||
mNetwork = other.mNetwork;
|
||||
mDisplayName = other.mDisplayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ProvisioningConfigurationParcelable from this ProvisioningConfiguration.
|
||||
*/
|
||||
public ProvisioningConfigurationParcelable toStableParcelable() {
|
||||
final ProvisioningConfigurationParcelable p = new ProvisioningConfigurationParcelable();
|
||||
p.enableIPv4 = mEnableIPv4;
|
||||
p.enableIPv6 = mEnableIPv6;
|
||||
p.usingMultinetworkPolicyTracker = mUsingMultinetworkPolicyTracker;
|
||||
p.usingIpReachabilityMonitor = mUsingIpReachabilityMonitor;
|
||||
p.requestedPreDhcpActionMs = mRequestedPreDhcpActionMs;
|
||||
p.initialConfig = mInitialConfig == null ? null : mInitialConfig.toStableParcelable();
|
||||
p.staticIpConfig = mStaticIpConfig == null
|
||||
? null
|
||||
: new StaticIpConfiguration(mStaticIpConfig);
|
||||
p.apfCapabilities = mApfCapabilities; // ApfCapabilities is immutable
|
||||
p.provisioningTimeoutMs = mProvisioningTimeoutMs;
|
||||
p.ipv6AddrGenMode = mIPv6AddrGenMode;
|
||||
p.network = mNetwork;
|
||||
p.displayName = mDisplayName;
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ProvisioningConfiguration from a ProvisioningConfigurationParcelable.
|
||||
*/
|
||||
public static ProvisioningConfiguration fromStableParcelable(
|
||||
@Nullable ProvisioningConfigurationParcelable p) {
|
||||
if (p == null) return null;
|
||||
final ProvisioningConfiguration config = new ProvisioningConfiguration();
|
||||
config.mEnableIPv4 = p.enableIPv4;
|
||||
config.mEnableIPv6 = p.enableIPv6;
|
||||
config.mUsingMultinetworkPolicyTracker = p.usingMultinetworkPolicyTracker;
|
||||
config.mUsingIpReachabilityMonitor = p.usingIpReachabilityMonitor;
|
||||
config.mRequestedPreDhcpActionMs = p.requestedPreDhcpActionMs;
|
||||
config.mInitialConfig = InitialConfiguration.fromStableParcelable(p.initialConfig);
|
||||
config.mStaticIpConfig = p.staticIpConfig == null
|
||||
? null
|
||||
: new StaticIpConfiguration(p.staticIpConfig);
|
||||
config.mApfCapabilities = p.apfCapabilities; // ApfCapabilities is immutable
|
||||
config.mProvisioningTimeoutMs = p.provisioningTimeoutMs;
|
||||
config.mIPv6AddrGenMode = p.ipv6AddrGenMode;
|
||||
config.mNetwork = p.network;
|
||||
config.mDisplayName = p.displayName;
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringJoiner(", ", getClass().getSimpleName() + "{", "}")
|
||||
.add("mEnableIPv4: " + mEnableIPv4)
|
||||
.add("mEnableIPv6: " + mEnableIPv6)
|
||||
.add("mUsingMultinetworkPolicyTracker: " + mUsingMultinetworkPolicyTracker)
|
||||
.add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor)
|
||||
.add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs)
|
||||
.add("mInitialConfig: " + mInitialConfig)
|
||||
.add("mStaticIpConfig: " + mStaticIpConfig)
|
||||
.add("mApfCapabilities: " + mApfCapabilities)
|
||||
.add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs)
|
||||
.add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
|
||||
.add("mNetwork: " + mNetwork)
|
||||
.add("mDisplayName: " + mDisplayName)
|
||||
.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ProvisioningConfiguration)) return false;
|
||||
final ProvisioningConfiguration other = (ProvisioningConfiguration) obj;
|
||||
return mEnableIPv4 == other.mEnableIPv4
|
||||
&& mEnableIPv6 == other.mEnableIPv6
|
||||
&& mUsingMultinetworkPolicyTracker == other.mUsingMultinetworkPolicyTracker
|
||||
&& mUsingIpReachabilityMonitor == other.mUsingIpReachabilityMonitor
|
||||
&& mRequestedPreDhcpActionMs == other.mRequestedPreDhcpActionMs
|
||||
&& Objects.equals(mInitialConfig, other.mInitialConfig)
|
||||
&& Objects.equals(mStaticIpConfig, other.mStaticIpConfig)
|
||||
&& Objects.equals(mApfCapabilities, other.mApfCapabilities)
|
||||
&& mProvisioningTimeoutMs == other.mProvisioningTimeoutMs
|
||||
&& mIPv6AddrGenMode == other.mIPv6AddrGenMode
|
||||
&& Objects.equals(mNetwork, other.mNetwork)
|
||||
&& Objects.equals(mDisplayName, other.mDisplayName);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return (mInitialConfig == null) || mInitialConfig.isValid();
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.net.util;
|
||||
|
||||
import static com.android.internal.util.Preconditions.checkArgument;
|
||||
|
||||
import android.net.MacAddress;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
|
||||
|
||||
/**
|
||||
* Encapsulate the interface parameters common to IpClient/IpServer components.
|
||||
*
|
||||
* Basically all java.net.NetworkInterface methods throw Exceptions. IpClient
|
||||
* and IpServer (sub)components need most or all of this information at some
|
||||
* point during their lifecycles, so pass only this simplified object around
|
||||
* which can be created once when IpClient/IpServer are told to start.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class InterfaceParams {
|
||||
public final String name;
|
||||
public final int index;
|
||||
public final MacAddress macAddr;
|
||||
public final int defaultMtu;
|
||||
|
||||
// TODO: move the below to NetworkStackConstants when this class is moved to the NetworkStack.
|
||||
private static final int ETHER_MTU = 1500;
|
||||
private static final int IPV6_MIN_MTU = 1280;
|
||||
|
||||
|
||||
public static InterfaceParams getByName(String name) {
|
||||
final NetworkInterface netif = getNetworkInterfaceByName(name);
|
||||
if (netif == null) return null;
|
||||
|
||||
// Not all interfaces have MAC addresses, e.g. rmnet_data0.
|
||||
final MacAddress macAddr = getMacAddress(netif);
|
||||
|
||||
try {
|
||||
return new InterfaceParams(name, netif.getIndex(), macAddr, netif.getMTU());
|
||||
} catch (IllegalArgumentException|SocketException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public InterfaceParams(String name, int index, MacAddress macAddr) {
|
||||
this(name, index, macAddr, ETHER_MTU);
|
||||
}
|
||||
|
||||
public InterfaceParams(String name, int index, MacAddress macAddr, int defaultMtu) {
|
||||
checkArgument((!TextUtils.isEmpty(name)), "impossible interface name");
|
||||
checkArgument((index > 0), "invalid interface index");
|
||||
this.name = name;
|
||||
this.index = index;
|
||||
this.macAddr = (macAddr != null) ? macAddr : MacAddress.fromBytes(new byte[] {
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00 });
|
||||
this.defaultMtu = (defaultMtu > IPV6_MIN_MTU) ? defaultMtu : IPV6_MIN_MTU;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s/%d/%s/%d", name, index, macAddr, defaultMtu);
|
||||
}
|
||||
|
||||
private static NetworkInterface getNetworkInterfaceByName(String name) {
|
||||
try {
|
||||
return NetworkInterface.getByName(name);
|
||||
} catch (NullPointerException|SocketException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static MacAddress getMacAddress(NetworkInterface netif) {
|
||||
try {
|
||||
return MacAddress.fromBytes(netif.getHardwareAddress());
|
||||
} catch (IllegalArgumentException|NullPointerException|SocketException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.net.util;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.LocalLog;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
|
||||
/**
|
||||
* Class to centralize logging functionality for tethering.
|
||||
*
|
||||
* All access to class methods other than dump() must be on the same thread.
|
||||
*
|
||||
* TODO: this is a copy of SharedLog in the NetworkStack. Remove after Tethering is migrated.
|
||||
* @hide
|
||||
*/
|
||||
public class SharedLog {
|
||||
private static final int DEFAULT_MAX_RECORDS = 500;
|
||||
private static final String COMPONENT_DELIMITER = ".";
|
||||
|
||||
private enum Category {
|
||||
NONE,
|
||||
ERROR,
|
||||
MARK,
|
||||
WARN,
|
||||
};
|
||||
|
||||
private final LocalLog mLocalLog;
|
||||
// The tag to use for output to the system log. This is not output to the
|
||||
// LocalLog because that would be redundant.
|
||||
private final String mTag;
|
||||
// The component (or subcomponent) of a system that is sharing this log.
|
||||
// This can grow in depth if components call forSubComponent() to obtain
|
||||
// their SharedLog instance. The tag is not included in the component for
|
||||
// brevity.
|
||||
private final String mComponent;
|
||||
|
||||
public SharedLog(String tag) {
|
||||
this(DEFAULT_MAX_RECORDS, tag);
|
||||
}
|
||||
|
||||
public SharedLog(int maxRecords, String tag) {
|
||||
this(new LocalLog(maxRecords), tag, tag);
|
||||
}
|
||||
|
||||
private SharedLog(LocalLog localLog, String tag, String component) {
|
||||
mLocalLog = localLog;
|
||||
mTag = tag;
|
||||
mComponent = component;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return mTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SharedLog based on this log with an additional component prefix on each logged line.
|
||||
*/
|
||||
public SharedLog forSubComponent(String component) {
|
||||
if (!isRootLogInstance()) {
|
||||
component = mComponent + COMPONENT_DELIMITER + component;
|
||||
}
|
||||
return new SharedLog(mLocalLog, mTag, component);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the contents of this log.
|
||||
*
|
||||
* <p>This method may be called on any thread.
|
||||
*/
|
||||
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
|
||||
mLocalLog.readOnlyLocalLog().dump(fd, writer, args);
|
||||
}
|
||||
|
||||
//////
|
||||
// Methods that both log an entry and emit it to the system log.
|
||||
//////
|
||||
|
||||
/**
|
||||
* Log an error due to an exception. This does not include the exception stacktrace.
|
||||
*
|
||||
* <p>The log entry will be also added to the system log.
|
||||
* @see #e(String, Throwable)
|
||||
*/
|
||||
public void e(Exception e) {
|
||||
Log.e(mTag, record(Category.ERROR, e.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an error message.
|
||||
*
|
||||
* <p>The log entry will be also added to the system log.
|
||||
*/
|
||||
public void e(String msg) {
|
||||
Log.e(mTag, record(Category.ERROR, msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an error due to an exception, with the exception stacktrace if provided.
|
||||
*
|
||||
* <p>The error and exception message appear in the shared log, but the stacktrace is only
|
||||
* logged in general log output (logcat). The log entry will be also added to the system log.
|
||||
*/
|
||||
public void e(@NonNull String msg, @Nullable Throwable exception) {
|
||||
if (exception == null) {
|
||||
e(msg);
|
||||
return;
|
||||
}
|
||||
Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an informational message.
|
||||
*
|
||||
* <p>The log entry will be also added to the system log.
|
||||
*/
|
||||
public void i(String msg) {
|
||||
Log.i(mTag, record(Category.NONE, msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a warning message.
|
||||
*
|
||||
* <p>The log entry will be also added to the system log.
|
||||
*/
|
||||
public void w(String msg) {
|
||||
Log.w(mTag, record(Category.WARN, msg));
|
||||
}
|
||||
|
||||
//////
|
||||
// Methods that only log an entry (and do NOT emit to the system log).
|
||||
//////
|
||||
|
||||
/**
|
||||
* Log a general message to be only included in the in-memory log.
|
||||
*
|
||||
* <p>The log entry will *not* be added to the system log.
|
||||
*/
|
||||
public void log(String msg) {
|
||||
record(Category.NONE, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a general, formatted message to be only included in the in-memory log.
|
||||
*
|
||||
* <p>The log entry will *not* be added to the system log.
|
||||
* @see String#format(String, Object...)
|
||||
*/
|
||||
public void logf(String fmt, Object... args) {
|
||||
log(String.format(fmt, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a message with MARK level.
|
||||
*
|
||||
* <p>The log entry will *not* be added to the system log.
|
||||
*/
|
||||
public void mark(String msg) {
|
||||
record(Category.MARK, msg);
|
||||
}
|
||||
|
||||
private String record(Category category, String msg) {
|
||||
final String entry = logLine(category, msg);
|
||||
mLocalLog.log(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
private String logLine(Category category, String msg) {
|
||||
final StringJoiner sj = new StringJoiner(" ");
|
||||
if (!isRootLogInstance()) sj.add("[" + mComponent + "]");
|
||||
if (category != Category.NONE) sj.add(category.toString());
|
||||
return sj.add(msg).toString();
|
||||
}
|
||||
|
||||
// Check whether this SharedLog instance is nominally the top level in
|
||||
// a potential hierarchy of shared logs (the root of a tree),
|
||||
// or is a subcomponent within the hierarchy.
|
||||
private boolean isRootLogInstance() {
|
||||
return TextUtils.isEmpty(mComponent) || mComponent.equals(mTag);
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 android.net.ip;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.net.INetd;
|
||||
import android.net.InetAddresses;
|
||||
import android.net.InterfaceConfigurationParcel;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.util.SharedLog;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class InterfaceControllerTest {
|
||||
private static final String TEST_IFACE = "testif";
|
||||
private static final String TEST_IPV4_ADDR = "192.168.123.28";
|
||||
private static final int TEST_PREFIXLENGTH = 31;
|
||||
|
||||
@Mock private INetd mNetd;
|
||||
@Mock private SharedLog mLog;
|
||||
@Captor private ArgumentCaptor<InterfaceConfigurationParcel> mConfigCaptor;
|
||||
|
||||
private InterfaceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mController = new InterfaceController(TEST_IFACE, mNetd, mLog);
|
||||
|
||||
doNothing().when(mNetd).interfaceSetCfg(mConfigCaptor.capture());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetIPv4Address() throws Exception {
|
||||
mController.setIPv4Address(
|
||||
new LinkAddress(InetAddresses.parseNumericAddress(TEST_IPV4_ADDR),
|
||||
TEST_PREFIXLENGTH));
|
||||
verify(mNetd, times(1)).interfaceSetCfg(any());
|
||||
final InterfaceConfigurationParcel parcel = mConfigCaptor.getValue();
|
||||
assertEquals(TEST_IFACE, parcel.ifName);
|
||||
assertEquals(TEST_IPV4_ADDR, parcel.ipv4Addr);
|
||||
assertEquals(TEST_PREFIXLENGTH, parcel.prefixLength);
|
||||
assertEquals("", parcel.hwAddr);
|
||||
assertArrayEquals(new String[0], parcel.flags);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearIPv4Address() throws Exception {
|
||||
mController.clearIPv4Address();
|
||||
verify(mNetd, times(1)).interfaceSetCfg(any());
|
||||
final InterfaceConfigurationParcel parcel = mConfigCaptor.getValue();
|
||||
assertEquals(TEST_IFACE, parcel.ifName);
|
||||
assertEquals("0.0.0.0", parcel.ipv4Addr);
|
||||
assertEquals(0, parcel.prefixLength);
|
||||
assertEquals("", parcel.hwAddr);
|
||||
assertArrayEquals(new String[0], parcel.flags);
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.net.netlink;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import android.system.OsConstants;
|
||||
|
||||
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.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class ConntrackMessageTest {
|
||||
private static final boolean USING_LE = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
// Example 1: TCP (192.168.43.209, 44333) -> (23.211.13.26, 443)
|
||||
public static final String CT_V4UPDATE_TCP_HEX =
|
||||
// struct nlmsghdr
|
||||
"50000000" + // length = 80
|
||||
"0001" + // type = (1 << 8) | 0
|
||||
"0501" + // flags
|
||||
"01000000" + // seqno = 1
|
||||
"00000000" + // pid = 0
|
||||
// struct nfgenmsg
|
||||
"02" + // nfgen_family = AF_INET
|
||||
"00" + // version = NFNETLINK_V0
|
||||
"0000" + // res_id
|
||||
// struct nlattr
|
||||
"3400" + // nla_len = 52
|
||||
"0180" + // nla_type = nested CTA_TUPLE_ORIG
|
||||
// struct nlattr
|
||||
"1400" + // nla_len = 20
|
||||
"0180" + // nla_type = nested CTA_TUPLE_IP
|
||||
"0800 0100 C0A82BD1" + // nla_type=CTA_IP_V4_SRC, ip=192.168.43.209
|
||||
"0800 0200 17D30D1A" + // nla_type=CTA_IP_V4_DST, ip=23.211.13.26
|
||||
// struct nlattr
|
||||
"1C00" + // nla_len = 28
|
||||
"0280" + // nla_type = nested CTA_TUPLE_PROTO
|
||||
"0500 0100 06 000000" + // nla_type=CTA_PROTO_NUM, proto=6
|
||||
"0600 0200 AD2D 0000" + // nla_type=CTA_PROTO_SRC_PORT, port=44333 (big endian)
|
||||
"0600 0300 01BB 0000" + // nla_type=CTA_PROTO_DST_PORT, port=443 (big endian)
|
||||
// struct nlattr
|
||||
"0800" + // nla_len = 8
|
||||
"0700" + // nla_type = CTA_TIMEOUT
|
||||
"00069780"; // nla_value = 432000 (big endian)
|
||||
public static final byte[] CT_V4UPDATE_TCP_BYTES =
|
||||
HexEncoding.decode(CT_V4UPDATE_TCP_HEX.replaceAll(" ", "").toCharArray(), false);
|
||||
|
||||
// Example 2: UDP (100.96.167.146, 37069) -> (216.58.197.10, 443)
|
||||
public static final String CT_V4UPDATE_UDP_HEX =
|
||||
// struct nlmsghdr
|
||||
"50000000" + // length = 80
|
||||
"0001" + // type = (1 << 8) | 0
|
||||
"0501" + // flags
|
||||
"01000000" + // seqno = 1
|
||||
"00000000" + // pid = 0
|
||||
// struct nfgenmsg
|
||||
"02" + // nfgen_family = AF_INET
|
||||
"00" + // version = NFNETLINK_V0
|
||||
"0000" + // res_id
|
||||
// struct nlattr
|
||||
"3400" + // nla_len = 52
|
||||
"0180" + // nla_type = nested CTA_TUPLE_ORIG
|
||||
// struct nlattr
|
||||
"1400" + // nla_len = 20
|
||||
"0180" + // nla_type = nested CTA_TUPLE_IP
|
||||
"0800 0100 6460A792" + // nla_type=CTA_IP_V4_SRC, ip=100.96.167.146
|
||||
"0800 0200 D83AC50A" + // nla_type=CTA_IP_V4_DST, ip=216.58.197.10
|
||||
// struct nlattr
|
||||
"1C00" + // nla_len = 28
|
||||
"0280" + // nla_type = nested CTA_TUPLE_PROTO
|
||||
"0500 0100 11 000000" + // nla_type=CTA_PROTO_NUM, proto=17
|
||||
"0600 0200 90CD 0000" + // nla_type=CTA_PROTO_SRC_PORT, port=37069 (big endian)
|
||||
"0600 0300 01BB 0000" + // nla_type=CTA_PROTO_DST_PORT, port=443 (big endian)
|
||||
// struct nlattr
|
||||
"0800" + // nla_len = 8
|
||||
"0700" + // nla_type = CTA_TIMEOUT
|
||||
"000000B4"; // nla_value = 180 (big endian)
|
||||
public static final byte[] CT_V4UPDATE_UDP_BYTES =
|
||||
HexEncoding.decode(CT_V4UPDATE_UDP_HEX.replaceAll(" ", "").toCharArray(), false);
|
||||
|
||||
@Test
|
||||
public void testConntrackIPv4TcpTimeoutUpdate() throws Exception {
|
||||
assumeTrue(USING_LE);
|
||||
|
||||
final byte[] tcp = ConntrackMessage.newIPv4TimeoutUpdateRequest(
|
||||
OsConstants.IPPROTO_TCP,
|
||||
(Inet4Address) InetAddress.getByName("192.168.43.209"), 44333,
|
||||
(Inet4Address) InetAddress.getByName("23.211.13.26"), 443,
|
||||
432000);
|
||||
assertArrayEquals(CT_V4UPDATE_TCP_BYTES, tcp);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConntrackIPv4UdpTimeoutUpdate() throws Exception {
|
||||
assumeTrue(USING_LE);
|
||||
|
||||
final byte[] udp = ConntrackMessage.newIPv4TimeoutUpdateRequest(
|
||||
OsConstants.IPPROTO_UDP,
|
||||
(Inet4Address) InetAddress.getByName("100.96.167.146"), 37069,
|
||||
(Inet4Address) InetAddress.getByName("216.58.197.10"), 443,
|
||||
180);
|
||||
assertArrayEquals(CT_V4UPDATE_UDP_BYTES, udp);
|
||||
}
|
||||
}
|
||||
@@ -1,448 +0,0 @@
|
||||
/*
|
||||
* 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 android.net.netlink;
|
||||
|
||||
import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
|
||||
import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
|
||||
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.SOCK_DGRAM;
|
||||
import static android.system.OsConstants.SOCK_STREAM;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.netlink.StructNlMsgHdr;
|
||||
import android.os.Process;
|
||||
import android.system.Os;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import libcore.util.HexEncoding;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class InetDiagSocketTest {
|
||||
private final String TAG = "InetDiagSocketTest";
|
||||
private ConnectivityManager mCm;
|
||||
private Context mContext;
|
||||
private final static int SOCKET_TIMEOUT_MS = 100;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
mContext = instrumentation.getTargetContext();
|
||||
mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
}
|
||||
|
||||
private class Connection {
|
||||
public int socketDomain;
|
||||
public int socketType;
|
||||
public InetAddress localAddress;
|
||||
public InetAddress remoteAddress;
|
||||
public InetAddress localhostAddress;
|
||||
public InetSocketAddress local;
|
||||
public InetSocketAddress remote;
|
||||
public int protocol;
|
||||
public FileDescriptor localFd;
|
||||
public FileDescriptor remoteFd;
|
||||
|
||||
public FileDescriptor createSocket() throws Exception {
|
||||
return Os.socket(socketDomain, socketType, protocol);
|
||||
}
|
||||
|
||||
public Connection(String to, String from) throws Exception {
|
||||
remoteAddress = InetAddress.getByName(to);
|
||||
if (from != null) {
|
||||
localAddress = InetAddress.getByName(from);
|
||||
} else {
|
||||
localAddress = (remoteAddress instanceof Inet4Address) ?
|
||||
Inet4Address.getByName("localhost") : Inet6Address.getByName("::");
|
||||
}
|
||||
if ((localAddress instanceof Inet4Address) && (remoteAddress instanceof Inet4Address)) {
|
||||
socketDomain = AF_INET;
|
||||
localhostAddress = Inet4Address.getByName("localhost");
|
||||
} else {
|
||||
socketDomain = AF_INET6;
|
||||
localhostAddress = Inet6Address.getByName("::");
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws Exception {
|
||||
Os.close(localFd);
|
||||
}
|
||||
}
|
||||
|
||||
private class TcpConnection extends Connection {
|
||||
public TcpConnection(String to, String from) throws Exception {
|
||||
super(to, from);
|
||||
protocol = IPPROTO_TCP;
|
||||
socketType = SOCK_STREAM;
|
||||
|
||||
remoteFd = createSocket();
|
||||
Os.bind(remoteFd, remoteAddress, 0);
|
||||
Os.listen(remoteFd, 10);
|
||||
int remotePort = ((InetSocketAddress) Os.getsockname(remoteFd)).getPort();
|
||||
|
||||
localFd = createSocket();
|
||||
Os.bind(localFd, localAddress, 0);
|
||||
Os.connect(localFd, remoteAddress, remotePort);
|
||||
|
||||
local = (InetSocketAddress) Os.getsockname(localFd);
|
||||
remote = (InetSocketAddress) Os.getpeername(localFd);
|
||||
}
|
||||
|
||||
public void close() throws Exception {
|
||||
super.close();
|
||||
Os.close(remoteFd);
|
||||
}
|
||||
}
|
||||
private class UdpConnection extends Connection {
|
||||
public UdpConnection(String to, String from) throws Exception {
|
||||
super(to, from);
|
||||
protocol = IPPROTO_UDP;
|
||||
socketType = SOCK_DGRAM;
|
||||
|
||||
remoteFd = null;
|
||||
localFd = createSocket();
|
||||
Os.bind(localFd, localAddress, 0);
|
||||
|
||||
Os.connect(localFd, remoteAddress, 7);
|
||||
local = (InetSocketAddress) Os.getsockname(localFd);
|
||||
remote = new InetSocketAddress(remoteAddress, 7);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkConnectionOwnerUid(int protocol, InetSocketAddress local,
|
||||
InetSocketAddress remote, boolean expectSuccess) {
|
||||
final int uid = mCm.getConnectionOwnerUid(protocol, local, remote);
|
||||
|
||||
if (expectSuccess) {
|
||||
assertEquals(Process.myUid(), uid);
|
||||
} else {
|
||||
assertNotEquals(Process.myUid(), uid);
|
||||
}
|
||||
}
|
||||
|
||||
private int findLikelyFreeUdpPort(UdpConnection conn) throws Exception {
|
||||
UdpConnection udp = new UdpConnection(conn.remoteAddress.getHostAddress(),
|
||||
conn.localAddress.getHostAddress());
|
||||
final int localPort = udp.local.getPort();
|
||||
udp.close();
|
||||
return localPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a test connection for UDP and TCP sockets and verify that this
|
||||
* {protocol, local, remote} socket result in receiving a valid UID.
|
||||
*/
|
||||
public void checkGetConnectionOwnerUid(String to, String from) throws Exception {
|
||||
TcpConnection tcp = new TcpConnection(to, from);
|
||||
checkConnectionOwnerUid(tcp.protocol, tcp.local, tcp.remote, true);
|
||||
checkConnectionOwnerUid(IPPROTO_UDP, tcp.local, tcp.remote, false);
|
||||
checkConnectionOwnerUid(tcp.protocol, new InetSocketAddress(0), tcp.remote, false);
|
||||
checkConnectionOwnerUid(tcp.protocol, tcp.local, new InetSocketAddress(0), false);
|
||||
tcp.close();
|
||||
|
||||
UdpConnection udp = new UdpConnection(to,from);
|
||||
checkConnectionOwnerUid(udp.protocol, udp.local, udp.remote, true);
|
||||
checkConnectionOwnerUid(IPPROTO_TCP, udp.local, udp.remote, false);
|
||||
checkConnectionOwnerUid(udp.protocol, new InetSocketAddress(findLikelyFreeUdpPort(udp)),
|
||||
udp.remote, false);
|
||||
udp.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetConnectionOwnerUid() throws Exception {
|
||||
checkGetConnectionOwnerUid("::", null);
|
||||
checkGetConnectionOwnerUid("::", "::");
|
||||
checkGetConnectionOwnerUid("0.0.0.0", null);
|
||||
checkGetConnectionOwnerUid("0.0.0.0", "0.0.0.0");
|
||||
checkGetConnectionOwnerUid("127.0.0.1", null);
|
||||
checkGetConnectionOwnerUid("127.0.0.1", "127.0.0.2");
|
||||
checkGetConnectionOwnerUid("::1", null);
|
||||
checkGetConnectionOwnerUid("::1", "::1");
|
||||
}
|
||||
|
||||
/* Verify fix for b/141603906 */
|
||||
@Test
|
||||
public void testB141603906() throws Exception {
|
||||
final InetSocketAddress src = new InetSocketAddress(0);
|
||||
final InetSocketAddress dst = new InetSocketAddress(0);
|
||||
final int numThreads = 8;
|
||||
final int numSockets = 5000;
|
||||
final Thread[] threads = new Thread[numThreads];
|
||||
|
||||
for (int i = 0; i < numThreads; i++) {
|
||||
threads[i] = new Thread(() -> {
|
||||
for (int j = 0; j < numSockets; j++) {
|
||||
mCm.getConnectionOwnerUid(IPPROTO_TCP, src, dst);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (Thread thread : threads) {
|
||||
thread.start();
|
||||
}
|
||||
|
||||
for (Thread thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
// 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_SPECIFED_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 (NullPointerException 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 (NullPointerException 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_SPECIFED_BYTES, msg);
|
||||
assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES, msgExt);
|
||||
}
|
||||
|
||||
// Hexadecimal representation of InetDiagReqV2 request.
|
||||
private static final String INET_DIAG_MSG_HEX =
|
||||
// struct nlmsghdr
|
||||
"58000000" + // length = 88
|
||||
"1400" + // type = SOCK_DIAG_BY_FAMILY
|
||||
"0200" + // flags = NLM_F_MULTI
|
||||
"00000000" + // seqno
|
||||
"f5220000" + // pid (0 == kernel)
|
||||
// struct inet_diag_msg
|
||||
"0a" + // family = AF_INET6
|
||||
"01" + // idiag_state
|
||||
"00" + // idiag_timer
|
||||
"00" + // idiag_retrans
|
||||
// inet_diag_sockid
|
||||
"a817" + // idiag_sport = 43031
|
||||
"960f" + // idiag_dport = 38415
|
||||
"fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b
|
||||
"00000000000000000000ffff08080808" + // idiag_dst = 8.8.8.8
|
||||
"00000000" + // idiag_if
|
||||
"ffffffffffffffff" + // idiag_cookie = INET_DIAG_NOCOOKIE
|
||||
"00000000" + // idiag_expires
|
||||
"00000000" + // idiag_rqueue
|
||||
"00000000" + // idiag_wqueue
|
||||
"a3270000" + // idiag_uid
|
||||
"A57E1900"; // idiag_inode
|
||||
private static final byte[] INET_DIAG_MSG_BYTES =
|
||||
HexEncoding.decode(INET_DIAG_MSG_HEX.toCharArray(), false);
|
||||
|
||||
@Test
|
||||
public void testParseInetDiagResponse() throws Exception {
|
||||
final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_BYTES);
|
||||
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
|
||||
assertNotNull(msg);
|
||||
|
||||
assertTrue(msg instanceof InetDiagMessage);
|
||||
final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg;
|
||||
assertEquals(10147, inetDiagMsg.mStructInetDiagMsg.idiag_uid);
|
||||
|
||||
final StructNlMsgHdr hdr = inetDiagMsg.getHeader();
|
||||
assertNotNull(hdr);
|
||||
assertEquals(NetlinkConstants.SOCK_DIAG_BY_FAMILY, hdr.nlmsg_type);
|
||||
assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags);
|
||||
assertEquals(0, hdr.nlmsg_seq);
|
||||
assertEquals(8949, hdr.nlmsg_pid);
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 android.net.netlink;
|
||||
|
||||
import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
|
||||
import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
|
||||
import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.net.netlink.NetlinkConstants;
|
||||
import android.net.netlink.NetlinkErrorMessage;
|
||||
import android.net.netlink.NetlinkMessage;
|
||||
import android.net.netlink.StructNlMsgErr;
|
||||
|
||||
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.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class NetlinkErrorMessageTest {
|
||||
private final String TAG = "NetlinkErrorMessageTest";
|
||||
|
||||
// Hexadecimal representation of packet capture.
|
||||
public static final String NLM_ERROR_OK_HEX =
|
||||
// struct nlmsghdr
|
||||
"24000000" + // length = 36
|
||||
"0200" + // type = 2 (NLMSG_ERROR)
|
||||
"0000" + // flags
|
||||
"26350000" + // seqno
|
||||
"64100000" + // pid = userspace process
|
||||
// error integer
|
||||
"00000000" + // "errno" (0 == OK)
|
||||
// struct nlmsghdr
|
||||
"30000000" + // length (48) of original request
|
||||
"1C00" + // type = 28 (RTM_NEWNEIGH)
|
||||
"0501" + // flags (NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE)
|
||||
"26350000" + // seqno
|
||||
"00000000"; // pid = kernel
|
||||
public static final byte[] NLM_ERROR_OK =
|
||||
HexEncoding.decode(NLM_ERROR_OK_HEX.toCharArray(), false);
|
||||
|
||||
@Test
|
||||
public void testParseNlmErrorOk() {
|
||||
final ByteBuffer byteBuffer = ByteBuffer.wrap(NLM_ERROR_OK);
|
||||
byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
|
||||
final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
|
||||
assertNotNull(msg);
|
||||
assertTrue(msg instanceof NetlinkErrorMessage);
|
||||
final NetlinkErrorMessage errorMsg = (NetlinkErrorMessage) msg;
|
||||
|
||||
final StructNlMsgHdr hdr = errorMsg.getHeader();
|
||||
assertNotNull(hdr);
|
||||
assertEquals(36, hdr.nlmsg_len);
|
||||
assertEquals(NetlinkConstants.NLMSG_ERROR, hdr.nlmsg_type);
|
||||
assertEquals(0, hdr.nlmsg_flags);
|
||||
assertEquals(13606, hdr.nlmsg_seq);
|
||||
assertEquals(4196, hdr.nlmsg_pid);
|
||||
|
||||
final StructNlMsgErr err = errorMsg.getNlMsgError();
|
||||
assertNotNull(err);
|
||||
assertEquals(0, err.error);
|
||||
assertNotNull(err.msg);
|
||||
assertEquals(48, err.msg.nlmsg_len);
|
||||
assertEquals(NetlinkConstants.RTM_NEWNEIGH, err.msg.nlmsg_type);
|
||||
assertEquals((NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE), err.msg.nlmsg_flags);
|
||||
assertEquals(13606, err.msg.nlmsg_seq);
|
||||
assertEquals(0, err.msg.nlmsg_pid);
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 android.net.netlink;
|
||||
|
||||
import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
|
||||
import static android.system.OsConstants.NETLINK_ROUTE;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.net.netlink.NetlinkSocket;
|
||||
import android.net.netlink.RtNetlinkNeighborMessage;
|
||||
import android.net.netlink.StructNlMsgHdr;
|
||||
import android.system.NetlinkSocketAddress;
|
||||
import android.system.Os;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class NetlinkSocketTest {
|
||||
private final String TAG = "NetlinkSocketTest";
|
||||
|
||||
@Test
|
||||
public void testBasicWorkingGetNeighborsQuery() throws Exception {
|
||||
final FileDescriptor fd = NetlinkSocket.forProto(NETLINK_ROUTE);
|
||||
assertNotNull(fd);
|
||||
|
||||
NetlinkSocket.connectToKernel(fd);
|
||||
|
||||
final NetlinkSocketAddress localAddr = (NetlinkSocketAddress) Os.getsockname(fd);
|
||||
assertNotNull(localAddr);
|
||||
assertEquals(0, localAddr.getGroupsMask());
|
||||
assertTrue(0 != localAddr.getPortId());
|
||||
|
||||
final int TEST_SEQNO = 5;
|
||||
final byte[] req = RtNetlinkNeighborMessage.newGetNeighborsRequest(TEST_SEQNO);
|
||||
assertNotNull(req);
|
||||
|
||||
final long TIMEOUT = 500;
|
||||
assertEquals(req.length, NetlinkSocket.sendMessage(fd, req, 0, req.length, TIMEOUT));
|
||||
|
||||
int neighMessageCount = 0;
|
||||
int doneMessageCount = 0;
|
||||
|
||||
while (doneMessageCount == 0) {
|
||||
ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT);
|
||||
assertNotNull(response);
|
||||
assertTrue(StructNlMsgHdr.STRUCT_SIZE <= response.limit());
|
||||
assertEquals(0, response.position());
|
||||
assertEquals(ByteOrder.nativeOrder(), response.order());
|
||||
|
||||
// Verify the messages at least appears minimally reasonable.
|
||||
while (response.remaining() > 0) {
|
||||
final NetlinkMessage msg = NetlinkMessage.parse(response);
|
||||
assertNotNull(msg);
|
||||
final StructNlMsgHdr hdr = msg.getHeader();
|
||||
assertNotNull(hdr);
|
||||
|
||||
if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) {
|
||||
doneMessageCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type);
|
||||
assertTrue(msg instanceof RtNetlinkNeighborMessage);
|
||||
assertTrue((hdr.nlmsg_flags & StructNlMsgHdr.NLM_F_MULTI) != 0);
|
||||
assertEquals(TEST_SEQNO, hdr.nlmsg_seq);
|
||||
assertEquals(localAddr.getPortId(), hdr.nlmsg_pid);
|
||||
|
||||
neighMessageCount++;
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(1, doneMessageCount);
|
||||
// TODO: make sure this test passes sanely in airplane mode.
|
||||
assertTrue(neighMessageCount > 0);
|
||||
|
||||
IoUtils.closeQuietly(fd);
|
||||
}
|
||||
}
|
||||
@@ -1,270 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 android.net.netlink;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.net.netlink.NetlinkConstants;
|
||||
import android.net.netlink.NetlinkMessage;
|
||||
import android.net.netlink.RtNetlinkNeighborMessage;
|
||||
import android.net.netlink.StructNdMsg;
|
||||
import android.net.netlink.StructNlMsgHdr;
|
||||
import android.system.OsConstants;
|
||||
|
||||
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.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class RtNetlinkNeighborMessageTest {
|
||||
private final String TAG = "RtNetlinkNeighborMessageTest";
|
||||
|
||||
// Hexadecimal representation of packet capture.
|
||||
public static final String RTM_DELNEIGH_HEX =
|
||||
// struct nlmsghdr
|
||||
"4c000000" + // length = 76
|
||||
"1d00" + // type = 29 (RTM_DELNEIGH)
|
||||
"0000" + // flags
|
||||
"00000000" + // seqno
|
||||
"00000000" + // pid (0 == kernel)
|
||||
// struct ndmsg
|
||||
"02" + // family
|
||||
"00" + // pad1
|
||||
"0000" + // pad2
|
||||
"15000000" + // interface index (21 == wlan0, on test device)
|
||||
"0400" + // NUD state (0x04 == NUD_STALE)
|
||||
"00" + // flags
|
||||
"01" + // type
|
||||
// struct nlattr: NDA_DST
|
||||
"0800" + // length = 8
|
||||
"0100" + // type (1 == NDA_DST, for neighbor messages)
|
||||
"c0a89ffe" + // IPv4 address (== 192.168.159.254)
|
||||
// struct nlattr: NDA_LLADDR
|
||||
"0a00" + // length = 10
|
||||
"0200" + // type (2 == NDA_LLADDR, for neighbor messages)
|
||||
"00005e000164" + // MAC Address (== 00:00:5e:00:01:64)
|
||||
"0000" + // padding, for 4 byte alignment
|
||||
// struct nlattr: NDA_PROBES
|
||||
"0800" + // length = 8
|
||||
"0400" + // type (4 == NDA_PROBES, for neighbor messages)
|
||||
"01000000" + // number of probes
|
||||
// struct nlattr: NDA_CACHEINFO
|
||||
"1400" + // length = 20
|
||||
"0300" + // type (3 == NDA_CACHEINFO, for neighbor messages)
|
||||
"05190000" + // ndm_used, as "clock ticks ago"
|
||||
"05190000" + // ndm_confirmed, as "clock ticks ago"
|
||||
"190d0000" + // ndm_updated, as "clock ticks ago"
|
||||
"00000000"; // ndm_refcnt
|
||||
public static final byte[] RTM_DELNEIGH =
|
||||
HexEncoding.decode(RTM_DELNEIGH_HEX.toCharArray(), false);
|
||||
|
||||
// Hexadecimal representation of packet capture.
|
||||
public static final String RTM_NEWNEIGH_HEX =
|
||||
// struct nlmsghdr
|
||||
"58000000" + // length = 88
|
||||
"1c00" + // type = 28 (RTM_NEWNEIGH)
|
||||
"0000" + // flags
|
||||
"00000000" + // seqno
|
||||
"00000000" + // pid (0 == kernel)
|
||||
// struct ndmsg
|
||||
"0a" + // family
|
||||
"00" + // pad1
|
||||
"0000" + // pad2
|
||||
"15000000" + // interface index (21 == wlan0, on test device)
|
||||
"0400" + // NUD state (0x04 == NUD_STALE)
|
||||
"80" + // flags
|
||||
"01" + // type
|
||||
// struct nlattr: NDA_DST
|
||||
"1400" + // length = 20
|
||||
"0100" + // type (1 == NDA_DST, for neighbor messages)
|
||||
"fe8000000000000086c9b2fffe6aed4b" + // IPv6 address (== fe80::86c9:b2ff:fe6a:ed4b)
|
||||
// struct nlattr: NDA_LLADDR
|
||||
"0a00" + // length = 10
|
||||
"0200" + // type (2 == NDA_LLADDR, for neighbor messages)
|
||||
"84c9b26aed4b" + // MAC Address (== 84:c9:b2:6a:ed:4b)
|
||||
"0000" + // padding, for 4 byte alignment
|
||||
// struct nlattr: NDA_PROBES
|
||||
"0800" + // length = 8
|
||||
"0400" + // type (4 == NDA_PROBES, for neighbor messages)
|
||||
"01000000" + // number of probes
|
||||
// struct nlattr: NDA_CACHEINFO
|
||||
"1400" + // length = 20
|
||||
"0300" + // type (3 == NDA_CACHEINFO, for neighbor messages)
|
||||
"eb0e0000" + // ndm_used, as "clock ticks ago"
|
||||
"861f0000" + // ndm_confirmed, as "clock ticks ago"
|
||||
"00000000" + // ndm_updated, as "clock ticks ago"
|
||||
"05000000"; // ndm_refcnt
|
||||
public static final byte[] RTM_NEWNEIGH =
|
||||
HexEncoding.decode(RTM_NEWNEIGH_HEX.toCharArray(), false);
|
||||
|
||||
// An example of the full response from an RTM_GETNEIGH query.
|
||||
private static final String RTM_GETNEIGH_RESPONSE_HEX =
|
||||
// <-- struct nlmsghr -->|<-- struct ndmsg -->|<-- struct nlattr: NDA_DST -->|<-- NDA_LLADDR -->|<-- NDA_PROBES -->|<-- NDA_CACHEINFO -->|
|
||||
"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" +
|
||||
"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" +
|
||||
"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" +
|
||||
"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" +
|
||||
"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" +
|
||||
"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" +
|
||||
"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" +
|
||||
"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" +
|
||||
"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" +
|
||||
"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" +
|
||||
"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" +
|
||||
"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" +
|
||||
"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" +
|
||||
"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";
|
||||
public static final byte[] RTM_GETNEIGH_RESPONSE =
|
||||
HexEncoding.decode(RTM_GETNEIGH_RESPONSE_HEX.replaceAll(" ", "").toCharArray(), false);
|
||||
|
||||
@Test
|
||||
public void testParseRtmDelNeigh() {
|
||||
final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_DELNEIGH);
|
||||
byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
|
||||
final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
|
||||
assertNotNull(msg);
|
||||
assertTrue(msg instanceof RtNetlinkNeighborMessage);
|
||||
final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
|
||||
|
||||
final StructNlMsgHdr hdr = neighMsg.getHeader();
|
||||
assertNotNull(hdr);
|
||||
assertEquals(76, hdr.nlmsg_len);
|
||||
assertEquals(NetlinkConstants.RTM_DELNEIGH, hdr.nlmsg_type);
|
||||
assertEquals(0, hdr.nlmsg_flags);
|
||||
assertEquals(0, hdr.nlmsg_seq);
|
||||
assertEquals(0, hdr.nlmsg_pid);
|
||||
|
||||
final StructNdMsg ndmsgHdr = neighMsg.getNdHeader();
|
||||
assertNotNull(ndmsgHdr);
|
||||
assertEquals((byte) OsConstants.AF_INET, ndmsgHdr.ndm_family);
|
||||
assertEquals(21, ndmsgHdr.ndm_ifindex);
|
||||
assertEquals(StructNdMsg.NUD_STALE, ndmsgHdr.ndm_state);
|
||||
final InetAddress destination = neighMsg.getDestination();
|
||||
assertNotNull(destination);
|
||||
assertEquals(InetAddress.parseNumericAddress("192.168.159.254"), destination);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseRtmNewNeigh() {
|
||||
final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_NEWNEIGH);
|
||||
byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
|
||||
final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
|
||||
assertNotNull(msg);
|
||||
assertTrue(msg instanceof RtNetlinkNeighborMessage);
|
||||
final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
|
||||
|
||||
final StructNlMsgHdr hdr = neighMsg.getHeader();
|
||||
assertNotNull(hdr);
|
||||
assertEquals(88, hdr.nlmsg_len);
|
||||
assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type);
|
||||
assertEquals(0, hdr.nlmsg_flags);
|
||||
assertEquals(0, hdr.nlmsg_seq);
|
||||
assertEquals(0, hdr.nlmsg_pid);
|
||||
|
||||
final StructNdMsg ndmsgHdr = neighMsg.getNdHeader();
|
||||
assertNotNull(ndmsgHdr);
|
||||
assertEquals((byte) OsConstants.AF_INET6, ndmsgHdr.ndm_family);
|
||||
assertEquals(21, ndmsgHdr.ndm_ifindex);
|
||||
assertEquals(StructNdMsg.NUD_STALE, ndmsgHdr.ndm_state);
|
||||
final InetAddress destination = neighMsg.getDestination();
|
||||
assertNotNull(destination);
|
||||
assertEquals(InetAddress.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), destination);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseRtmGetNeighResponse() {
|
||||
final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_GETNEIGH_RESPONSE);
|
||||
byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
|
||||
|
||||
int messageCount = 0;
|
||||
while (byteBuffer.remaining() > 0) {
|
||||
final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
|
||||
assertNotNull(msg);
|
||||
assertTrue(msg instanceof RtNetlinkNeighborMessage);
|
||||
final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
|
||||
|
||||
final StructNlMsgHdr hdr = neighMsg.getHeader();
|
||||
assertNotNull(hdr);
|
||||
assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type);
|
||||
assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags);
|
||||
assertEquals(0, hdr.nlmsg_seq);
|
||||
assertEquals(11070, hdr.nlmsg_pid);
|
||||
|
||||
messageCount++;
|
||||
}
|
||||
// TODO: add more detailed spot checks.
|
||||
assertEquals(14, messageCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateRtmNewNeighMessage() {
|
||||
final int seqNo = 2635;
|
||||
final int ifIndex = 14;
|
||||
final byte[] llAddr =
|
||||
new byte[] { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6 };
|
||||
|
||||
// Hexadecimal representation of our created packet.
|
||||
final String expectedNewNeighHex =
|
||||
// struct nlmsghdr
|
||||
"30000000" + // length = 48
|
||||
"1c00" + // type = 28 (RTM_NEWNEIGH)
|
||||
"0501" + // flags (NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE)
|
||||
"4b0a0000" + // seqno
|
||||
"00000000" + // pid (0 == kernel)
|
||||
// struct ndmsg
|
||||
"02" + // family
|
||||
"00" + // pad1
|
||||
"0000" + // pad2
|
||||
"0e000000" + // interface index (14)
|
||||
"0800" + // NUD state (0x08 == NUD_DELAY)
|
||||
"00" + // flags
|
||||
"00" + // type
|
||||
// struct nlattr: NDA_DST
|
||||
"0800" + // length = 8
|
||||
"0100" + // type (1 == NDA_DST, for neighbor messages)
|
||||
"7f000001" + // IPv4 address (== 127.0.0.1)
|
||||
// struct nlattr: NDA_LLADDR
|
||||
"0a00" + // length = 10
|
||||
"0200" + // type (2 == NDA_LLADDR, for neighbor messages)
|
||||
"010203040506" + // MAC Address (== 01:02:03:04:05:06)
|
||||
"0000"; // padding, for 4 byte alignment
|
||||
final byte[] expectedNewNeigh =
|
||||
HexEncoding.decode(expectedNewNeighHex.toCharArray(), false);
|
||||
|
||||
final byte[] bytes = RtNetlinkNeighborMessage.newNewNeighborMessage(
|
||||
seqNo, Inet4Address.LOOPBACK, StructNdMsg.NUD_DELAY, ifIndex, llAddr);
|
||||
if (!Arrays.equals(expectedNewNeigh, bytes)) {
|
||||
assertEquals(expectedNewNeigh.length, bytes.length);
|
||||
for (int i = 0; i < Math.min(expectedNewNeigh.length, bytes.length); i++) {
|
||||
assertEquals(expectedNewNeigh[i], bytes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 android.net.shared;
|
||||
|
||||
import static android.net.shared.Inet4AddressUtils.getBroadcastAddress;
|
||||
import static android.net.shared.Inet4AddressUtils.getImplicitNetmask;
|
||||
import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address;
|
||||
import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
|
||||
import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTL;
|
||||
import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
|
||||
import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTL;
|
||||
import static android.net.shared.Inet4AddressUtils.netmaskToPrefixLength;
|
||||
import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH;
|
||||
import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.net.InetAddresses;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class Inet4AddressUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testInet4AddressToIntHTL() {
|
||||
assertEquals(0, inet4AddressToIntHTL(ipv4Address("0.0.0.0")));
|
||||
assertEquals(0x000080ff, inet4AddressToIntHTL(ipv4Address("255.128.0.0")));
|
||||
assertEquals(0x0080ff0a, inet4AddressToIntHTL(ipv4Address("10.255.128.0")));
|
||||
assertEquals(0x00feff0a, inet4AddressToIntHTL(ipv4Address("10.255.254.0")));
|
||||
assertEquals(0xfeffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.254")));
|
||||
assertEquals(0xffffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.255")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntToInet4AddressHTL() {
|
||||
assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTL(0));
|
||||
assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTL(0x000080ff));
|
||||
assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTL(0x0080ff0a));
|
||||
assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTL(0x00feff0a));
|
||||
assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTL(0xfeffa8c0));
|
||||
assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTL(0xffffa8c0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInet4AddressToIntHTH() {
|
||||
assertEquals(0, inet4AddressToIntHTH(ipv4Address("0.0.0.0")));
|
||||
assertEquals(0xff800000, inet4AddressToIntHTH(ipv4Address("255.128.0.0")));
|
||||
assertEquals(0x0aff8000, inet4AddressToIntHTH(ipv4Address("10.255.128.0")));
|
||||
assertEquals(0x0afffe00, inet4AddressToIntHTH(ipv4Address("10.255.254.0")));
|
||||
assertEquals(0xc0a8fffe, inet4AddressToIntHTH(ipv4Address("192.168.255.254")));
|
||||
assertEquals(0xc0a8ffff, inet4AddressToIntHTH(ipv4Address("192.168.255.255")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntToInet4AddressHTH() {
|
||||
assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTH(0));
|
||||
assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTH(0xff800000));
|
||||
assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTH(0x0aff8000));
|
||||
assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTH(0x0afffe00));
|
||||
assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTH(0xc0a8fffe));
|
||||
assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTH(0xc0a8ffff));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPrefixLengthToV4NetmaskIntHTL() {
|
||||
assertEquals(0, prefixLengthToV4NetmaskIntHTL(0));
|
||||
assertEquals(0x000080ff /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTL(9));
|
||||
assertEquals(0x0080ffff /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTL(17));
|
||||
assertEquals(0x00feffff /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTL(23));
|
||||
assertEquals(0xfeffffff /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTL(31));
|
||||
assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTL(32));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrefixLengthToV4NetmaskIntHTH() {
|
||||
assertEquals(0, prefixLengthToV4NetmaskIntHTH(0));
|
||||
assertEquals(0xff800000 /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTH(9));
|
||||
assertEquals(0xffff8000 /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTH(17));
|
||||
assertEquals(0xfffffe00 /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTH(23));
|
||||
assertEquals(0xfffffffe /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTH(31));
|
||||
assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTH(32));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testPrefixLengthToV4NetmaskIntHTH_NegativeLength() {
|
||||
prefixLengthToV4NetmaskIntHTH(-1);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testPrefixLengthToV4NetmaskIntHTH_LengthTooLarge() {
|
||||
prefixLengthToV4NetmaskIntHTH(33);
|
||||
}
|
||||
|
||||
private void checkAddressMasking(String expectedAddr, String addr, int prefixLength) {
|
||||
final int prefix = prefixLengthToV4NetmaskIntHTH(prefixLength);
|
||||
final int addrInt = inet4AddressToIntHTH(ipv4Address(addr));
|
||||
assertEquals(ipv4Address(expectedAddr), intToInet4AddressHTH(prefix & addrInt));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrefixLengthToV4NetmaskIntHTH_MaskAddr() {
|
||||
checkAddressMasking("192.168.0.0", "192.168.128.1", 16);
|
||||
checkAddressMasking("255.240.0.0", "255.255.255.255", 12);
|
||||
checkAddressMasking("255.255.255.255", "255.255.255.255", 32);
|
||||
checkAddressMasking("0.0.0.0", "255.255.255.255", 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetImplicitNetmask() {
|
||||
assertEquals(8, getImplicitNetmask(ipv4Address("4.2.2.2")));
|
||||
assertEquals(8, getImplicitNetmask(ipv4Address("10.5.6.7")));
|
||||
assertEquals(16, getImplicitNetmask(ipv4Address("173.194.72.105")));
|
||||
assertEquals(16, getImplicitNetmask(ipv4Address("172.23.68.145")));
|
||||
assertEquals(24, getImplicitNetmask(ipv4Address("192.0.2.1")));
|
||||
assertEquals(24, getImplicitNetmask(ipv4Address("192.168.5.1")));
|
||||
assertEquals(32, getImplicitNetmask(ipv4Address("224.0.0.1")));
|
||||
assertEquals(32, getImplicitNetmask(ipv4Address("255.6.7.8")));
|
||||
}
|
||||
|
||||
private void assertInvalidNetworkMask(Inet4Address addr) {
|
||||
try {
|
||||
netmaskToPrefixLength(addr);
|
||||
fail("Invalid netmask " + addr.getHostAddress() + " did not cause exception");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNetmaskToPrefixLength() {
|
||||
assertEquals(0, netmaskToPrefixLength(ipv4Address("0.0.0.0")));
|
||||
assertEquals(9, netmaskToPrefixLength(ipv4Address("255.128.0.0")));
|
||||
assertEquals(17, netmaskToPrefixLength(ipv4Address("255.255.128.0")));
|
||||
assertEquals(23, netmaskToPrefixLength(ipv4Address("255.255.254.0")));
|
||||
assertEquals(31, netmaskToPrefixLength(ipv4Address("255.255.255.254")));
|
||||
assertEquals(32, netmaskToPrefixLength(ipv4Address("255.255.255.255")));
|
||||
|
||||
assertInvalidNetworkMask(ipv4Address("0.0.0.1"));
|
||||
assertInvalidNetworkMask(ipv4Address("255.255.255.253"));
|
||||
assertInvalidNetworkMask(ipv4Address("255.255.0.255"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPrefixMaskAsAddress() {
|
||||
assertEquals("255.255.240.0", getPrefixMaskAsInet4Address(20).getHostAddress());
|
||||
assertEquals("255.0.0.0", getPrefixMaskAsInet4Address(8).getHostAddress());
|
||||
assertEquals("0.0.0.0", getPrefixMaskAsInet4Address(0).getHostAddress());
|
||||
assertEquals("255.255.255.255", getPrefixMaskAsInet4Address(32).getHostAddress());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBroadcastAddress() {
|
||||
assertEquals("192.168.15.255",
|
||||
getBroadcastAddress(ipv4Address("192.168.0.123"), 20).getHostAddress());
|
||||
assertEquals("192.255.255.255",
|
||||
getBroadcastAddress(ipv4Address("192.168.0.123"), 8).getHostAddress());
|
||||
assertEquals("192.168.0.123",
|
||||
getBroadcastAddress(ipv4Address("192.168.0.123"), 32).getHostAddress());
|
||||
assertEquals("255.255.255.255",
|
||||
getBroadcastAddress(ipv4Address("192.168.0.123"), 0).getHostAddress());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testGetBroadcastAddress_PrefixTooLarge() {
|
||||
getBroadcastAddress(ipv4Address("192.168.0.123"), 33);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testGetBroadcastAddress_NegativePrefix() {
|
||||
getBroadcastAddress(ipv4Address("192.168.0.123"), -1);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testGetPrefixMaskAsAddress_PrefixTooLarge() {
|
||||
getPrefixMaskAsInet4Address(33);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testGetPrefixMaskAsAddress_NegativePrefix() {
|
||||
getPrefixMaskAsInet4Address(-1);
|
||||
}
|
||||
|
||||
private Inet4Address ipv4Address(String addr) {
|
||||
return (Inet4Address) InetAddresses.parseNumericAddress(addr);
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 android.net.shared;
|
||||
|
||||
import static android.net.InetAddresses.parseNumericAddress;
|
||||
|
||||
import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import android.net.IpPrefix;
|
||||
import android.net.LinkAddress;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Tests for {@link InitialConfiguration}
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class InitialConfigurationTest {
|
||||
private InitialConfiguration mConfig;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mConfig = new InitialConfiguration();
|
||||
mConfig.ipAddresses.addAll(Arrays.asList(
|
||||
new LinkAddress(parseNumericAddress("192.168.45.45"), 16),
|
||||
new LinkAddress(parseNumericAddress("2001:db8::45"), 33)));
|
||||
mConfig.directlyConnectedRoutes.addAll(Arrays.asList(
|
||||
new IpPrefix(parseNumericAddress("192.168.46.46"), 17),
|
||||
new IpPrefix(parseNumericAddress("2001:db8::46"), 34)));
|
||||
mConfig.dnsServers.addAll(Arrays.asList(
|
||||
parseNumericAddress("192.168.47.47"),
|
||||
parseNumericAddress("2001:db8::47")));
|
||||
// Any added InitialConfiguration field must be included in equals() to be tested properly
|
||||
assertFieldCountEquals(3, InitialConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelUnparcelInitialConfiguration() {
|
||||
final InitialConfiguration unparceled =
|
||||
InitialConfiguration.fromStableParcelable(mConfig.toStableParcelable());
|
||||
assertEquals(mConfig, unparceled);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
assertEquals(mConfig, InitialConfiguration.copy(mConfig));
|
||||
|
||||
assertNotEqualsAfterChange(c -> c.ipAddresses.add(
|
||||
new LinkAddress(parseNumericAddress("192.168.47.47"), 24)));
|
||||
assertNotEqualsAfterChange(c -> c.directlyConnectedRoutes.add(
|
||||
new IpPrefix(parseNumericAddress("192.168.46.46"), 32)));
|
||||
assertNotEqualsAfterChange(c -> c.dnsServers.add(parseNumericAddress("2001:db8::49")));
|
||||
assertFieldCountEquals(3, InitialConfiguration.class);
|
||||
}
|
||||
|
||||
private void assertNotEqualsAfterChange(Consumer<InitialConfiguration> mutator) {
|
||||
final InitialConfiguration newConfig = InitialConfiguration.copy(mConfig);
|
||||
mutator.accept(newConfig);
|
||||
assertNotEquals(mConfig, newConfig);
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 android.net.shared;
|
||||
|
||||
import static android.net.InetAddresses.parseNumericAddress;
|
||||
import static android.net.shared.IpConfigurationParcelableUtil.fromStableParcelable;
|
||||
import static android.net.shared.IpConfigurationParcelableUtil.toStableParcelable;
|
||||
|
||||
import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.net.DhcpResults;
|
||||
import android.net.LinkAddress;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
|
||||
/**
|
||||
* Tests for {@link IpConfigurationParcelableUtil}.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class IpConfigurationParcelableUtilTest {
|
||||
private DhcpResults mDhcpResults;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mDhcpResults = new DhcpResults();
|
||||
mDhcpResults.ipAddress = new LinkAddress(parseNumericAddress("2001:db8::42"), 64);
|
||||
mDhcpResults.gateway = parseNumericAddress("192.168.42.42");
|
||||
mDhcpResults.dnsServers.add(parseNumericAddress("2001:db8::43"));
|
||||
mDhcpResults.dnsServers.add(parseNumericAddress("192.168.43.43"));
|
||||
mDhcpResults.domains = "example.com";
|
||||
mDhcpResults.serverAddress = (Inet4Address) parseNumericAddress("192.168.44.44");
|
||||
mDhcpResults.vendorInfo = "TEST_VENDOR_INFO";
|
||||
mDhcpResults.leaseDuration = 3600;
|
||||
mDhcpResults.serverHostName = "dhcp.example.com";
|
||||
mDhcpResults.mtu = 1450;
|
||||
// Any added DhcpResults field must be included in equals() to be tested properly
|
||||
assertFieldCountEquals(9, DhcpResults.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelUnparcelDhcpResults() {
|
||||
doDhcpResultsParcelUnparcelTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelUnparcelDhcpResults_NullIpAddress() {
|
||||
mDhcpResults.ipAddress = null;
|
||||
doDhcpResultsParcelUnparcelTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelUnparcelDhcpResults_NullGateway() {
|
||||
mDhcpResults.gateway = null;
|
||||
doDhcpResultsParcelUnparcelTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelUnparcelDhcpResults_NullDomains() {
|
||||
mDhcpResults.domains = null;
|
||||
doDhcpResultsParcelUnparcelTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelUnparcelDhcpResults_EmptyDomains() {
|
||||
mDhcpResults.domains = "";
|
||||
doDhcpResultsParcelUnparcelTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelUnparcelDhcpResults_NullServerAddress() {
|
||||
mDhcpResults.serverAddress = null;
|
||||
doDhcpResultsParcelUnparcelTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelUnparcelDhcpResults_NullVendorInfo() {
|
||||
mDhcpResults.vendorInfo = null;
|
||||
doDhcpResultsParcelUnparcelTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelUnparcelDhcpResults_NullServerHostName() {
|
||||
mDhcpResults.serverHostName = null;
|
||||
doDhcpResultsParcelUnparcelTest();
|
||||
}
|
||||
|
||||
private void doDhcpResultsParcelUnparcelTest() {
|
||||
final DhcpResults unparceled = fromStableParcelable(toStableParcelable(mDhcpResults));
|
||||
assertEquals(mDhcpResults, unparceled);
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 android.net.shared;
|
||||
|
||||
import static android.net.InetAddresses.parseNumericAddress;
|
||||
import static android.net.shared.ProvisioningConfiguration.fromStableParcelable;
|
||||
|
||||
import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import android.net.LinkAddress;
|
||||
import android.net.Network;
|
||||
import android.net.StaticIpConfiguration;
|
||||
import android.net.apf.ApfCapabilities;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Tests for {@link ProvisioningConfiguration}.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class ProvisioningConfigurationTest {
|
||||
private ProvisioningConfiguration mConfig;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mConfig = new ProvisioningConfiguration();
|
||||
mConfig.mEnableIPv4 = true;
|
||||
mConfig.mEnableIPv6 = true;
|
||||
mConfig.mUsingMultinetworkPolicyTracker = true;
|
||||
mConfig.mUsingIpReachabilityMonitor = true;
|
||||
mConfig.mRequestedPreDhcpActionMs = 42;
|
||||
mConfig.mInitialConfig = new InitialConfiguration();
|
||||
mConfig.mInitialConfig.ipAddresses.add(
|
||||
new LinkAddress(parseNumericAddress("192.168.42.42"), 24));
|
||||
mConfig.mStaticIpConfig = new StaticIpConfiguration();
|
||||
mConfig.mStaticIpConfig.ipAddress =
|
||||
new LinkAddress(parseNumericAddress("2001:db8::42"), 90);
|
||||
// Not testing other InitialConfig or StaticIpConfig members: they have their own unit tests
|
||||
mConfig.mApfCapabilities = new ApfCapabilities(1, 2, 3);
|
||||
mConfig.mProvisioningTimeoutMs = 4200;
|
||||
mConfig.mIPv6AddrGenMode = 123;
|
||||
mConfig.mNetwork = new Network(321);
|
||||
mConfig.mDisplayName = "test_config";
|
||||
// Any added field must be included in equals() to be tested properly
|
||||
assertFieldCountEquals(12, ProvisioningConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelUnparcel() {
|
||||
doParcelUnparcelTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelUnparcel_NullInitialConfiguration() {
|
||||
mConfig.mInitialConfig = null;
|
||||
doParcelUnparcelTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelUnparcel_NullStaticConfiguration() {
|
||||
mConfig.mStaticIpConfig = null;
|
||||
doParcelUnparcelTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelUnparcel_NullApfCapabilities() {
|
||||
mConfig.mApfCapabilities = null;
|
||||
doParcelUnparcelTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelUnparcel_NullNetwork() {
|
||||
mConfig.mNetwork = null;
|
||||
doParcelUnparcelTest();
|
||||
}
|
||||
|
||||
private void doParcelUnparcelTest() {
|
||||
final ProvisioningConfiguration unparceled =
|
||||
fromStableParcelable(mConfig.toStableParcelable());
|
||||
assertEquals(mConfig, unparceled);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
assertEquals(mConfig, new ProvisioningConfiguration(mConfig));
|
||||
|
||||
assertNotEqualsAfterChange(c -> c.mEnableIPv4 = false);
|
||||
assertNotEqualsAfterChange(c -> c.mEnableIPv6 = false);
|
||||
assertNotEqualsAfterChange(c -> c.mUsingMultinetworkPolicyTracker = false);
|
||||
assertNotEqualsAfterChange(c -> c.mUsingIpReachabilityMonitor = false);
|
||||
assertNotEqualsAfterChange(c -> c.mRequestedPreDhcpActionMs++);
|
||||
assertNotEqualsAfterChange(c -> c.mInitialConfig.ipAddresses.add(
|
||||
new LinkAddress(parseNumericAddress("192.168.47.47"), 16)));
|
||||
assertNotEqualsAfterChange(c -> c.mInitialConfig = null);
|
||||
assertNotEqualsAfterChange(c -> c.mStaticIpConfig.ipAddress =
|
||||
new LinkAddress(parseNumericAddress("2001:db8::47"), 64));
|
||||
assertNotEqualsAfterChange(c -> c.mStaticIpConfig = null);
|
||||
assertNotEqualsAfterChange(c -> c.mApfCapabilities = new ApfCapabilities(4, 5, 6));
|
||||
assertNotEqualsAfterChange(c -> c.mApfCapabilities = null);
|
||||
assertNotEqualsAfterChange(c -> c.mProvisioningTimeoutMs++);
|
||||
assertNotEqualsAfterChange(c -> c.mIPv6AddrGenMode++);
|
||||
assertNotEqualsAfterChange(c -> c.mNetwork = new Network(123));
|
||||
assertNotEqualsAfterChange(c -> c.mNetwork = null);
|
||||
assertNotEqualsAfterChange(c -> c.mDisplayName = "other_test");
|
||||
assertNotEqualsAfterChange(c -> c.mDisplayName = null);
|
||||
assertFieldCountEquals(12, ProvisioningConfiguration.class);
|
||||
}
|
||||
|
||||
private void assertNotEqualsAfterChange(Consumer<ProvisioningConfiguration> mutator) {
|
||||
final ProvisioningConfiguration newConfig = new ProvisioningConfiguration(mConfig);
|
||||
mutator.accept(newConfig);
|
||||
assertNotEquals(mConfig, newConfig);
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.net.util;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class InterfaceParamsTest {
|
||||
@Test
|
||||
public void testNullInterfaceReturnsNull() {
|
||||
assertNull(InterfaceParams.getByName(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonExistentInterfaceReturnsNull() {
|
||||
assertNull(InterfaceParams.getByName("doesnotexist0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoopback() {
|
||||
final InterfaceParams ifParams = InterfaceParams.getByName("lo");
|
||||
assertNotNull(ifParams);
|
||||
assertEquals("lo", ifParams.name);
|
||||
assertTrue(ifParams.index > 0);
|
||||
assertNotNull(ifParams.macAddr);
|
||||
assertTrue(ifParams.defaultMtu >= NetworkConstants.ETHER_MTU);
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.net.util;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class SharedLogTest {
|
||||
private static final String TIMESTAMP_PATTERN = "\\d{2}:\\d{2}:\\d{2}";
|
||||
private static final String TIMESTAMP = "HH:MM:SS";
|
||||
|
||||
@Test
|
||||
public void testBasicOperation() {
|
||||
final SharedLog logTop = new SharedLog("top");
|
||||
logTop.mark("first post!");
|
||||
|
||||
final SharedLog logLevel2a = logTop.forSubComponent("twoA");
|
||||
final SharedLog logLevel2b = logTop.forSubComponent("twoB");
|
||||
logLevel2b.e("2b or not 2b");
|
||||
logLevel2b.e("No exception", null);
|
||||
logLevel2b.e("Wait, here's one", new Exception("Test"));
|
||||
logLevel2a.w("second post?");
|
||||
|
||||
final SharedLog logLevel3 = logLevel2a.forSubComponent("three");
|
||||
logTop.log("still logging");
|
||||
logLevel3.log("3 >> 2");
|
||||
logLevel2a.mark("ok: last post");
|
||||
|
||||
final String[] expected = {
|
||||
" - MARK first post!",
|
||||
" - [twoB] ERROR 2b or not 2b",
|
||||
" - [twoB] ERROR No exception",
|
||||
// No stacktrace in shared log, only in logcat
|
||||
" - [twoB] ERROR Wait, here's one: Test",
|
||||
" - [twoA] WARN second post?",
|
||||
" - still logging",
|
||||
" - [twoA.three] 3 >> 2",
|
||||
" - [twoA] MARK ok: last post",
|
||||
};
|
||||
// Verify the logs are all there and in the correct order.
|
||||
verifyLogLines(expected, logTop);
|
||||
|
||||
// In fact, because they all share the same underlying LocalLog,
|
||||
// every subcomponent SharedLog's dump() is identical.
|
||||
verifyLogLines(expected, logLevel2a);
|
||||
verifyLogLines(expected, logLevel2b);
|
||||
verifyLogLines(expected, logLevel3);
|
||||
}
|
||||
|
||||
private static void verifyLogLines(String[] expected, SharedLog log) {
|
||||
final ByteArrayOutputStream ostream = new ByteArrayOutputStream();
|
||||
final PrintWriter pw = new PrintWriter(ostream, true);
|
||||
log.dump(null, pw, null);
|
||||
|
||||
final String dumpOutput = ostream.toString();
|
||||
assertTrue(dumpOutput != null);
|
||||
assertTrue(!"".equals(dumpOutput));
|
||||
|
||||
final String[] lines = dumpOutput.split("\n");
|
||||
assertEquals(expected.length, lines.length);
|
||||
|
||||
for (int i = 0; i < expected.length; i++) {
|
||||
String got = lines[i];
|
||||
String want = expected[i];
|
||||
assertTrue(String.format("'%s' did not contain '%s'", got, want), got.endsWith(want));
|
||||
assertTrue(String.format("'%s' did not contain a %s timestamp", got, TIMESTAMP),
|
||||
got.replaceFirst(TIMESTAMP_PATTERN, TIMESTAMP).contains(TIMESTAMP));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user