diff options
Diffstat (limited to 'common/device/com/android/net/module/util/netlink')
28 files changed, 0 insertions, 5178 deletions
diff --git a/common/device/com/android/net/module/util/netlink/ConntrackMessage.java b/common/device/com/android/net/module/util/netlink/ConntrackMessage.java deleted file mode 100644 index dfed3efb..00000000 --- a/common/device/com/android/net/module/util/netlink/ConntrackMessage.java +++ /dev/null @@ -1,560 +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 com.android.net.module.util.netlink; - -import static android.system.OsConstants.IPPROTO_TCP; -import static android.system.OsConstants.IPPROTO_UDP; - -import static com.android.net.module.util.netlink.StructNlAttr.findNextAttrOfType; -import static com.android.net.module.util.netlink.StructNlAttr.makeNestedType; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REPLACE; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; - -import static java.nio.ByteOrder.BIG_ENDIAN; - -import android.system.OsConstants; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - -import java.net.Inet4Address; -import java.net.InetAddress; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Objects; - -/** - * 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; - - // enum ctattr_type - public static final short CTA_TUPLE_ORIG = 1; - public static final short CTA_TUPLE_REPLY = 2; - public static final short CTA_STATUS = 3; - 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; - - // enum ip_conntrack_status - public static final int IPS_EXPECTED = 0x00000001; - public static final int IPS_SEEN_REPLY = 0x00000002; - public static final int IPS_ASSURED = 0x00000004; - public static final int IPS_CONFIRMED = 0x00000008; - public static final int IPS_SRC_NAT = 0x00000010; - public static final int IPS_DST_NAT = 0x00000020; - public static final int IPS_SEQ_ADJUST = 0x00000040; - public static final int IPS_SRC_NAT_DONE = 0x00000080; - public static final int IPS_DST_NAT_DONE = 0x00000100; - public static final int IPS_DYING = 0x00000200; - public static final int IPS_FIXED_TIMEOUT = 0x00000400; - public static final int IPS_TEMPLATE = 0x00000800; - public static final int IPS_UNTRACKED = 0x00001000; - public static final int IPS_HELPER = 0x00002000; - public static final int IPS_OFFLOAD = 0x00004000; - public static final int IPS_HW_OFFLOAD = 0x00008000; - - // ip_conntrack_status mask - // Interesting on the NAT conntrack session which has already seen two direction traffic. - // TODO: Probably IPS_{SRC, DST}_NAT_DONE are also interesting. - public static final int ESTABLISHED_MASK = IPS_CONFIRMED | IPS_ASSURED | IPS_SEEN_REPLY - | IPS_SRC_NAT; - // Interesting on the established NAT conntrack session which is dying. - public static final int DYING_MASK = ESTABLISHED_MASK | IPS_DYING; - - /** - * A tuple for the conntrack connection information. - * - * see also CTA_TUPLE_ORIG and CTA_TUPLE_REPLY. - */ - public static class Tuple { - public final Inet4Address srcIp; - public final Inet4Address dstIp; - - // Both port and protocol number are unsigned numbers stored in signed integers, and that - // callers that want to compare them to integers should either cast those integers, or - // convert them to unsigned using Byte.toUnsignedInt() and Short.toUnsignedInt(). - public final short srcPort; - public final short dstPort; - public final byte protoNum; - - public Tuple(TupleIpv4 ip, TupleProto proto) { - this.srcIp = ip.src; - this.dstIp = ip.dst; - this.srcPort = proto.srcPort; - this.dstPort = proto.dstPort; - this.protoNum = proto.protoNum; - } - - @Override - @VisibleForTesting - public boolean equals(Object o) { - if (!(o instanceof Tuple)) return false; - Tuple that = (Tuple) o; - return Objects.equals(this.srcIp, that.srcIp) - && Objects.equals(this.dstIp, that.dstIp) - && this.srcPort == that.srcPort - && this.dstPort == that.dstPort - && this.protoNum == that.protoNum; - } - - @Override - public int hashCode() { - return Objects.hash(srcIp, dstIp, srcPort, dstPort, protoNum); - } - - @Override - public String toString() { - final String srcIpStr = (srcIp == null) ? "null" : srcIp.getHostAddress(); - final String dstIpStr = (dstIp == null) ? "null" : dstIp.getHostAddress(); - final String protoStr = NetlinkConstants.stringForProtocol(protoNum); - - return "Tuple{" - + protoStr + ": " - + srcIpStr + ":" + Short.toUnsignedInt(srcPort) + " -> " - + dstIpStr + ":" + Short.toUnsignedInt(dstPort) - + "}"; - } - } - - /** - * A tuple for the conntrack connection address. - * - * see also CTA_TUPLE_IP. - */ - public static class TupleIpv4 { - public final Inet4Address src; - public final Inet4Address dst; - - public TupleIpv4(Inet4Address src, Inet4Address dst) { - this.src = src; - this.dst = dst; - } - } - - /** - * A tuple for the conntrack connection protocol. - * - * see also CTA_TUPLE_PROTO. - */ - public static class TupleProto { - public final byte protoNum; - public final short srcPort; - public final short dstPort; - - public TupleProto(byte protoNum, short srcPort, short dstPort) { - this.protoNum = protoNum; - this.srcPort = srcPort; - this.dstPort = dstPort; - } - } - - /** - * Create a netlink message to refresh IPv4 conntrack entry timeout. - */ - 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 = (NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8) - | NetlinkConstants.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; - } - - /** - * Parses a netfilter conntrack message from a {@link ByteBuffer}. - * - * @param header the netlink message header. - * @param byteBuffer The buffer from which to parse the netfilter conntrack message. - * @return the parsed netfilter conntrack message, or {@code null} if the netfilter conntrack - * message could not be parsed successfully (for example, if it was truncated). - */ - @Nullable - public static ConntrackMessage parse(@NonNull StructNlMsgHdr header, - @NonNull ByteBuffer byteBuffer) { - // Just build the netlink header and netfilter header for now and pretend the whole message - // was consumed. - // TODO: Parse the conntrack attributes. - final StructNfGenMsg nfGenMsg = StructNfGenMsg.parse(byteBuffer); - if (nfGenMsg == null) { - return null; - } - - final int baseOffset = byteBuffer.position(); - StructNlAttr nlAttr = findNextAttrOfType(CTA_STATUS, byteBuffer); - int status = 0; - if (nlAttr != null) { - status = nlAttr.getValueAsBe32(0); - } - - byteBuffer.position(baseOffset); - nlAttr = findNextAttrOfType(CTA_TIMEOUT, byteBuffer); - int timeoutSec = 0; - if (nlAttr != null) { - timeoutSec = nlAttr.getValueAsBe32(0); - } - - byteBuffer.position(baseOffset); - nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_ORIG), byteBuffer); - Tuple tupleOrig = null; - if (nlAttr != null) { - tupleOrig = parseTuple(nlAttr.getValueAsByteBuffer()); - } - - byteBuffer.position(baseOffset); - nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_REPLY), byteBuffer); - Tuple tupleReply = null; - if (nlAttr != null) { - tupleReply = parseTuple(nlAttr.getValueAsByteBuffer()); - } - - // Advance to the end of the message. - byteBuffer.position(baseOffset); - final int kMinConsumed = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE; - final int kAdditionalSpace = NetlinkConstants.alignedLengthOf( - header.nlmsg_len - kMinConsumed); - if (byteBuffer.remaining() < kAdditionalSpace) { - return null; - } - byteBuffer.position(baseOffset + kAdditionalSpace); - - return new ConntrackMessage(header, nfGenMsg, tupleOrig, tupleReply, status, timeoutSec); - } - - /** - * Parses a conntrack tuple from a {@link ByteBuffer}. - * - * The attribute parsing is interesting on: - * - CTA_TUPLE_IP - * CTA_IP_V4_SRC - * CTA_IP_V4_DST - * - CTA_TUPLE_PROTO - * CTA_PROTO_NUM - * CTA_PROTO_SRC_PORT - * CTA_PROTO_DST_PORT - * - * Assume that the minimum size is the sum of CTA_TUPLE_IP (size: 20) and CTA_TUPLE_PROTO - * (size: 28). Here is an example for an expected CTA_TUPLE_ORIG message in raw data: - * +--------------------------------------------------------------------------------------+ - * | CTA_TUPLE_ORIG | - * +--------------------------+-----------------------------------------------------------+ - * | 1400 | nla_len = 20 | - * | 0180 | nla_type = nested CTA_TUPLE_IP | - * | 0800 0100 C0A8500C | nla_type=CTA_IP_V4_SRC, ip=192.168.80.12 | - * | 0800 0200 8C700874 | nla_type=CTA_IP_V4_DST, ip=140.112.8.116 | - * | 1C00 | nla_len = 28 | - * | 0280 | nla_type = nested CTA_TUPLE_PROTO | - * | 0500 0100 06 000000 | nla_type=CTA_PROTO_NUM, proto=IPPROTO_TCP (6) | - * | 0600 0200 F3F1 0000 | nla_type=CTA_PROTO_SRC_PORT, port=62449 (big endian) | - * | 0600 0300 01BB 0000 | nla_type=CTA_PROTO_DST_PORT, port=433 (big endian) | - * +--------------------------+-----------------------------------------------------------+ - * - * The position of the byte buffer doesn't set to the end when the function returns. It is okay - * because the caller ConntrackMessage#parse has passed a copy which is used for this parser - * only. Moreover, the parser behavior is the same as other existing netlink struct class - * parser. Ex: StructInetDiagMsg#parse. - */ - @Nullable - private static Tuple parseTuple(@Nullable ByteBuffer byteBuffer) { - if (byteBuffer == null) return null; - - TupleIpv4 tupleIpv4 = null; - TupleProto tupleProto = null; - - final int baseOffset = byteBuffer.position(); - StructNlAttr nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_IP), byteBuffer); - if (nlAttr != null) { - tupleIpv4 = parseTupleIpv4(nlAttr.getValueAsByteBuffer()); - } - if (tupleIpv4 == null) return null; - - byteBuffer.position(baseOffset); - nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_PROTO), byteBuffer); - if (nlAttr != null) { - tupleProto = parseTupleProto(nlAttr.getValueAsByteBuffer()); - } - if (tupleProto == null) return null; - - return new Tuple(tupleIpv4, tupleProto); - } - - @Nullable - private static Inet4Address castToInet4Address(@Nullable InetAddress address) { - if (address == null || !(address instanceof Inet4Address)) return null; - return (Inet4Address) address; - } - - @Nullable - private static TupleIpv4 parseTupleIpv4(@Nullable ByteBuffer byteBuffer) { - if (byteBuffer == null) return null; - - Inet4Address src = null; - Inet4Address dst = null; - - final int baseOffset = byteBuffer.position(); - StructNlAttr nlAttr = findNextAttrOfType(CTA_IP_V4_SRC, byteBuffer); - if (nlAttr != null) { - src = castToInet4Address(nlAttr.getValueAsInetAddress()); - } - if (src == null) return null; - - byteBuffer.position(baseOffset); - nlAttr = findNextAttrOfType(CTA_IP_V4_DST, byteBuffer); - if (nlAttr != null) { - dst = castToInet4Address(nlAttr.getValueAsInetAddress()); - } - if (dst == null) return null; - - return new TupleIpv4(src, dst); - } - - @Nullable - private static TupleProto parseTupleProto(@Nullable ByteBuffer byteBuffer) { - if (byteBuffer == null) return null; - - byte protoNum = 0; - short srcPort = 0; - short dstPort = 0; - - final int baseOffset = byteBuffer.position(); - StructNlAttr nlAttr = findNextAttrOfType(CTA_PROTO_NUM, byteBuffer); - if (nlAttr != null) { - protoNum = nlAttr.getValueAsByte((byte) 0); - } - if (!(protoNum == IPPROTO_TCP || protoNum == IPPROTO_UDP)) return null; - - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(CTA_PROTO_SRC_PORT, byteBuffer); - if (nlAttr != null) { - srcPort = nlAttr.getValueAsBe16((short) 0); - } - if (srcPort == 0) return null; - - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(CTA_PROTO_DST_PORT, byteBuffer); - if (nlAttr != null) { - dstPort = nlAttr.getValueAsBe16((short) 0); - } - if (dstPort == 0) return null; - - return new TupleProto(protoNum, srcPort, dstPort); - } - - /** - * Netfilter header. - */ - public final StructNfGenMsg nfGenMsg; - /** - * Original direction conntrack tuple. - * - * The tuple is determined by the parsed attribute value CTA_TUPLE_ORIG, or null if the - * tuple could not be parsed successfully (for example, if it was truncated or absent). - */ - @Nullable - public final Tuple tupleOrig; - /** - * Reply direction conntrack tuple. - * - * The tuple is determined by the parsed attribute value CTA_TUPLE_REPLY, or null if the - * tuple could not be parsed successfully (for example, if it was truncated or absent). - */ - @Nullable - public final Tuple tupleReply; - /** - * Connection status. A bitmask of ip_conntrack_status enum flags. - * - * The status is determined by the parsed attribute value CTA_STATUS, or 0 if the status could - * not be parsed successfully (for example, if it was truncated or absent). For the message - * from kernel, the valid status is non-zero. For the message from user space, the status may - * be 0 (absent). - */ - public final int status; - /** - * Conntrack timeout. - * - * The timeout is determined by the parsed attribute value CTA_TIMEOUT, or 0 if the timeout - * could not be parsed successfully (for example, if it was truncated or absent). For - * IPCTNL_MSG_CT_NEW event, the valid timeout is non-zero. For IPCTNL_MSG_CT_DELETE event, the - * timeout is 0 (absent). - */ - public final int timeoutSec; - - private ConntrackMessage() { - super(new StructNlMsgHdr()); - nfGenMsg = new StructNfGenMsg((byte) OsConstants.AF_INET); - - // This constructor is only used by #newIPv4TimeoutUpdateRequest which doesn't use these - // data member for packing message. Simply fill them to null or 0. - tupleOrig = null; - tupleReply = null; - status = 0; - timeoutSec = 0; - } - - private ConntrackMessage(@NonNull StructNlMsgHdr header, @NonNull StructNfGenMsg nfGenMsg, - @Nullable Tuple tupleOrig, @Nullable Tuple tupleReply, int status, int timeoutSec) { - super(header); - this.nfGenMsg = nfGenMsg; - this.tupleOrig = tupleOrig; - this.tupleReply = tupleReply; - this.status = status; - this.timeoutSec = timeoutSec; - } - - /** - * Write a netfilter message to {@link ByteBuffer}. - */ - public void pack(ByteBuffer byteBuffer) { - mHeader.pack(byteBuffer); - nfGenMsg.pack(byteBuffer); - } - - public short getMessageType() { - return (short) (getHeader().nlmsg_type & ~(NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8)); - } - - /** - * Convert an ip conntrack status to a string. - */ - public static String stringForIpConntrackStatus(int flags) { - final StringBuilder sb = new StringBuilder(); - - if ((flags & IPS_EXPECTED) != 0) { - sb.append("IPS_EXPECTED"); - } - if ((flags & IPS_SEEN_REPLY) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_SEEN_REPLY"); - } - if ((flags & IPS_ASSURED) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_ASSURED"); - } - if ((flags & IPS_CONFIRMED) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_CONFIRMED"); - } - if ((flags & IPS_SRC_NAT) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_SRC_NAT"); - } - if ((flags & IPS_DST_NAT) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_DST_NAT"); - } - if ((flags & IPS_SEQ_ADJUST) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_SEQ_ADJUST"); - } - if ((flags & IPS_SRC_NAT_DONE) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_SRC_NAT_DONE"); - } - if ((flags & IPS_DST_NAT_DONE) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_DST_NAT_DONE"); - } - if ((flags & IPS_DYING) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_DYING"); - } - if ((flags & IPS_FIXED_TIMEOUT) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_FIXED_TIMEOUT"); - } - if ((flags & IPS_TEMPLATE) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_TEMPLATE"); - } - if ((flags & IPS_UNTRACKED) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_UNTRACKED"); - } - if ((flags & IPS_HELPER) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_HELPER"); - } - if ((flags & IPS_OFFLOAD) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_OFFLOAD"); - } - if ((flags & IPS_HW_OFFLOAD) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_HW_OFFLOAD"); - } - return sb.toString(); - } - - @Override - public String toString() { - return "ConntrackMessage{" - + "nlmsghdr{" - + (mHeader == null ? "" : mHeader.toString(OsConstants.NETLINK_NETFILTER)) - + "}, " - + "nfgenmsg{" + nfGenMsg + "}, " - + "tuple_orig{" + tupleOrig + "}, " - + "tuple_reply{" + tupleReply + "}, " - + "status{" + status + "(" + stringForIpConntrackStatus(status) + ")" + "}, " - + "timeout_sec{" + Integer.toUnsignedLong(timeoutSec) + "}" - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/InetDiagMessage.java b/common/device/com/android/net/module/util/netlink/InetDiagMessage.java deleted file mode 100644 index f8b47164..00000000 --- a/common/device/com/android/net/module/util/netlink/InetDiagMessage.java +++ /dev/null @@ -1,505 +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 com.android.net.module.util.netlink; - -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.ENOENT; -import static android.system.OsConstants.IPPROTO_TCP; -import static android.system.OsConstants.IPPROTO_UDP; -import static android.system.OsConstants.NETLINK_INET_DIAG; - -import static com.android.net.module.util.netlink.NetlinkConstants.NLMSG_DONE; -import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DESTROY; -import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY; -import static com.android.net.module.util.netlink.NetlinkConstants.hexify; -import static com.android.net.module.util.netlink.NetlinkConstants.stringForAddressFamily; -import static com.android.net.module.util.netlink.NetlinkConstants.stringForProtocol; -import static com.android.net.module.util.netlink.NetlinkUtils.DEFAULT_RECV_BUFSIZE; -import static com.android.net.module.util.netlink.NetlinkUtils.IO_TIMEOUT_MS; -import static com.android.net.module.util.netlink.NetlinkUtils.TCP_ALIVE_STATE_FILTER; -import static com.android.net.module.util.netlink.NetlinkUtils.connectSocketToNetlink; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; - -import android.net.util.SocketUtils; -import android.os.Process; -import android.os.SystemClock; -import android.system.ErrnoException; -import android.util.Log; -import android.util.Range; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.List; -import java.util.Set; -import java.util.function.Predicate; - -/** - * 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; - - /** - * Construct an inet_diag_req_v2 message. This method will throw - * {@link IllegalArgumentException} if local and remote are not both null or both non-null. - */ - 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 IllegalArgumentException} 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 - * {@link 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 - * {@link 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 IllegalArgumentException { - // 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 IllegalArgumentException( - "Local and remote must be both null or both non-null"); - } - final StructInetDiagSockId id = ((local != null && remote != null) - ? new StructInetDiagSockId(local, remote) : null); - return inetDiagReqV2(protocol, id, family, - SOCK_DIAG_BY_FAMILY, flags, pad, idiagExt, state); - } - - /** - * Construct an inet_diag_req_v2 message. - * - * @param protocol the request protocol type. This should be set to one of IPPROTO_TCP, - * IPPROTO_UDP, or IPPROTO_UDPLITE. - * @param id inet_diag_sockid. See {@link StructInetDiagSockId} - * @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 type message types. - * @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 StructInetDiagSockId id, int family, - short type, short flags, int pad, int idiagExt, int state) { - 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 = type; - nlMsgHdr.nlmsg_flags = flags; - nlMsgHdr.pack(byteBuffer); - final StructInetDiagReqV2 inetDiagReqV2 = - new StructInetDiagReqV2(protocol, id, family, pad, idiagExt, state); - - inetDiagReqV2.pack(byteBuffer); - return bytes; - } - - public StructInetDiagMsg inetDiagMsg; - - @VisibleForTesting - public InetDiagMessage(@NonNull StructNlMsgHdr header) { - super(header); - inetDiagMsg = new StructInetDiagMsg(); - } - - /** - * Parse an inet_diag_req_v2 message from buffer. - */ - @Nullable - public static InetDiagMessage parse(@NonNull StructNlMsgHdr header, - @NonNull ByteBuffer byteBuffer) { - final InetDiagMessage msg = new InetDiagMessage(header); - msg.inetDiagMsg = StructInetDiagMsg.parse(byteBuffer); - if (msg.inetDiagMsg == null) { - return null; - } - return msg; - } - - private static void closeSocketQuietly(final FileDescriptor fd) { - try { - SocketUtils.closeSocket(fd); - } catch (IOException ignored) { - } - } - - 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); - NetlinkUtils.sendMessage(fd, msg, 0, msg.length, TIMEOUT_MS); - ByteBuffer response = NetlinkUtils.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT_MS); - - final NetlinkMessage nlMsg = NetlinkMessage.parse(response, NETLINK_INET_DIAG); - if (nlMsg == null) { - return INVALID_UID; - } - final StructNlMsgHdr hdr = nlMsg.getHeader(); - if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) { - return INVALID_UID; - } - if (nlMsg instanceof InetDiagMessage) { - return ((InetDiagMessage) nlMsg).inetDiagMsg.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 = NetlinkUtils.netlinkSocketForProto(NETLINK_INET_DIAG); - NetlinkUtils.connectSocketToNetlink(fd); - uid = lookupUid(protocol, local, remote, fd); - } catch (ErrnoException | SocketException | IllegalArgumentException - | InterruptedIOException e) { - Log.e(TAG, e.toString()); - } finally { - closeSocketQuietly(fd); - } - return uid; - } - - /** - * Construct an inet_diag_req_v2 message for querying alive TCP sockets from kernel. - */ - public static byte[] buildInetDiagReqForAliveTcpSockets(int family) { - return inetDiagReqV2(IPPROTO_TCP, - null /* local addr */, - null /* remote addr */, - family, - (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_DUMP) /* flag */, - 0 /* pad */, - 1 << NetlinkConstants.INET_DIAG_MEMINFO /* idiagExt */, - TCP_ALIVE_STATE_FILTER); - } - - private static void sendNetlinkDestroyRequest(FileDescriptor fd, int proto, - InetDiagMessage diagMsg) throws InterruptedIOException, ErrnoException { - final byte[] destroyMsg = InetDiagMessage.inetDiagReqV2( - proto, - diagMsg.inetDiagMsg.id, - diagMsg.inetDiagMsg.idiag_family, - SOCK_DESTROY, - (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_ACK), - 0 /* pad */, - 0 /* idiagExt */, - 1 << diagMsg.inetDiagMsg.idiag_state - ); - NetlinkUtils.sendMessage(fd, destroyMsg, 0, destroyMsg.length, IO_TIMEOUT_MS); - NetlinkUtils.receiveNetlinkAck(fd); - } - - private static void sendNetlinkDumpRequest(FileDescriptor fd, int proto, int states, int family) - throws InterruptedIOException, ErrnoException { - final byte[] dumpMsg = InetDiagMessage.inetDiagReqV2( - proto, - null /* id */, - family, - SOCK_DIAG_BY_FAMILY, - (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_DUMP), - 0 /* pad */, - 0 /* idiagExt */, - states); - NetlinkUtils.sendMessage(fd, dumpMsg, 0, dumpMsg.length, IO_TIMEOUT_MS); - } - - private static int processNetlinkDumpAndDestroySockets(FileDescriptor dumpFd, - FileDescriptor destroyFd, int proto, Predicate<InetDiagMessage> filter) - throws InterruptedIOException, ErrnoException { - int destroyedSockets = 0; - - while (true) { - final ByteBuffer buf = NetlinkUtils.recvMessage( - dumpFd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT_MS); - - while (buf.remaining() > 0) { - final int position = buf.position(); - final NetlinkMessage nlMsg = NetlinkMessage.parse(buf, NETLINK_INET_DIAG); - if (nlMsg == null) { - // Move to the position where parse started for error log. - buf.position(position); - Log.e(TAG, "Failed to parse netlink message: " + hexify(buf)); - break; - } - - if (nlMsg.getHeader().nlmsg_type == NLMSG_DONE) { - return destroyedSockets; - } - - if (!(nlMsg instanceof InetDiagMessage)) { - Log.wtf(TAG, "Received unexpected netlink message: " + nlMsg); - continue; - } - - final InetDiagMessage diagMsg = (InetDiagMessage) nlMsg; - if (filter.test(diagMsg)) { - try { - sendNetlinkDestroyRequest(destroyFd, proto, diagMsg); - destroyedSockets++; - } catch (InterruptedIOException | ErrnoException e) { - if (!(e instanceof ErrnoException - && ((ErrnoException) e).errno == ENOENT)) { - Log.e(TAG, "Failed to destroy socket: diagMsg=" + diagMsg + ", " + e); - } - } - } - } - } - } - - /** - * Returns whether the InetDiagMessage is for adb socket or not - */ - @VisibleForTesting - public static boolean isAdbSocket(final InetDiagMessage msg) { - // This is inaccurate since adb could run with ROOT_UID or other services can run with - // SHELL_UID. But this check covers most cases and enough. - // Note that getting service.adb.tcp.port system property is prohibited by sepolicy - // TODO: skip the socket only if there is a listen socket owned by SHELL_UID with the same - // source port as this socket - return msg.inetDiagMsg.idiag_uid == Process.SHELL_UID; - } - - /** - * Returns whether the range contains the uid in the InetDiagMessage or not - */ - @VisibleForTesting - public static boolean containsUid(InetDiagMessage msg, Set<Range<Integer>> ranges) { - for (final Range<Integer> range: ranges) { - if (range.contains(msg.inetDiagMsg.idiag_uid)) { - return true; - } - } - return false; - } - - private static boolean isLoopbackAddress(InetAddress addr) { - if (addr.isLoopbackAddress()) return true; - if (!(addr instanceof Inet6Address)) return false; - - // Following check is for v4-mapped v6 address. StructInetDiagSockId contains v4-mapped v6 - // address as Inet6Address, See StructInetDiagSockId#parse - final byte[] addrBytes = addr.getAddress(); - for (int i = 0; i < 10; i++) { - if (addrBytes[i] != 0) return false; - } - return addrBytes[10] == (byte) 0xff - && addrBytes[11] == (byte) 0xff - && addrBytes[12] == 127; - } - - /** - * Returns whether the socket address in the InetDiagMessage is loopback or not - */ - @VisibleForTesting - public static boolean isLoopback(InetDiagMessage msg) { - final InetAddress srcAddr = msg.inetDiagMsg.id.locSocketAddress.getAddress(); - final InetAddress dstAddr = msg.inetDiagMsg.id.remSocketAddress.getAddress(); - return isLoopbackAddress(srcAddr) - || isLoopbackAddress(dstAddr) - || srcAddr.equals(dstAddr); - } - - private static void destroySockets(int proto, int states, Predicate<InetDiagMessage> filter) - throws ErrnoException, SocketException, InterruptedIOException { - FileDescriptor dumpFd = null; - FileDescriptor destroyFd = null; - - try { - dumpFd = NetlinkUtils.createNetLinkInetDiagSocket(); - destroyFd = NetlinkUtils.createNetLinkInetDiagSocket(); - connectSocketToNetlink(dumpFd); - connectSocketToNetlink(destroyFd); - - for (int family : List.of(AF_INET, AF_INET6)) { - try { - sendNetlinkDumpRequest(dumpFd, proto, states, family); - } catch (InterruptedIOException | ErrnoException e) { - Log.e(TAG, "Failed to send netlink dump request: " + e); - continue; - } - final int destroyedSockets = processNetlinkDumpAndDestroySockets( - dumpFd, destroyFd, proto, filter); - Log.d(TAG, "Destroyed " + destroyedSockets + " sockets" - + ", proto=" + stringForProtocol(proto) - + ", family=" + stringForAddressFamily(family) - + ", states=" + states); - } - } finally { - closeSocketQuietly(dumpFd); - closeSocketQuietly(destroyFd); - } - } - - /** - * Close tcp sockets that match the following condition - * 1. TCP status is one of TCP_ESTABLISHED, TCP_SYN_SENT, and TCP_SYN_RECV - * 2. Owner uid of socket is not in the exemptUids - * 3. Owner uid of socket is in the ranges - * 4. Socket is not loopback - * 5. Socket is not adb socket - * - * @param ranges target uid ranges - * @param exemptUids uids to skip close socket - */ - public static void destroyLiveTcpSockets(Set<Range<Integer>> ranges, Set<Integer> exemptUids) - throws SocketException, InterruptedIOException, ErrnoException { - final long startTimeMs = SystemClock.elapsedRealtime(); - destroySockets(IPPROTO_TCP, TCP_ALIVE_STATE_FILTER, - (diagMsg) -> !exemptUids.contains(diagMsg.inetDiagMsg.idiag_uid) - && containsUid(diagMsg, ranges) - && !isLoopback(diagMsg) - && !isAdbSocket(diagMsg)); - final long durationMs = SystemClock.elapsedRealtime() - startTimeMs; - Log.d(TAG, "Destroyed live tcp sockets for uids=" + ranges + " exemptUids=" + exemptUids - + " in " + durationMs + "ms"); - } - - /** - * Close tcp sockets that match the following condition - * 1. TCP status is one of TCP_ESTABLISHED, TCP_SYN_SENT, and TCP_SYN_RECV - * 2. Owner uid of socket is in the targetUids - * 3. Socket is not loopback - * 4. Socket is not adb socket - * - * @param ownerUids target uids to close sockets - */ - public static void destroyLiveTcpSocketsByOwnerUids(Set<Integer> ownerUids) - throws SocketException, InterruptedIOException, ErrnoException { - final long startTimeMs = SystemClock.elapsedRealtime(); - destroySockets(IPPROTO_TCP, TCP_ALIVE_STATE_FILTER, - (diagMsg) -> ownerUids.contains(diagMsg.inetDiagMsg.idiag_uid) - && !isLoopback(diagMsg) - && !isAdbSocket(diagMsg)); - final long durationMs = SystemClock.elapsedRealtime() - startTimeMs; - Log.d(TAG, "Destroyed live tcp sockets for uids=" + ownerUids + " in " + durationMs + "ms"); - } - - @Override - public String toString() { - return "InetDiagMessage{ " - + "nlmsghdr{" - + (mHeader == null ? "" : mHeader.toString(NETLINK_INET_DIAG)) + "}, " - + "inet_diag_msg{" - + (inetDiagMsg == null ? "" : inetDiagMsg.toString()) + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/NdOption.java b/common/device/com/android/net/module/util/netlink/NdOption.java deleted file mode 100644 index defc88a7..00000000 --- a/common/device/com/android/net/module/util/netlink/NdOption.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; - -import java.nio.ByteBuffer; - -/** - * Base class for IPv6 neighbour discovery options. - */ -public class NdOption { - public static final int STRUCT_SIZE = 2; - - /** The option type. */ - public final byte type; - /** The length of the option in 8-byte units. Actually an unsigned 8-bit integer */ - public final int length; - - /** Constructs a new NdOption. */ - NdOption(byte type, int length) { - this.type = type; - this.length = length; - } - - /** - * Parses a neighbour discovery option. - * - * Parses (and consumes) the option if it is of a known type. If the option is of an unknown - * type, advances the buffer (so the caller can continue parsing if desired) and returns - * {@link #UNKNOWN}. If the option claims a length of 0, returns null because parsing cannot - * continue. - * - * No checks are performed on the length other than ensuring it is not 0, so if a caller wants - * to deal with options that might overflow the structure that contains them, it must explicitly - * set the buffer's limit to the position at which that structure ends. - * - * @param buf the buffer to parse. - * @return a subclass of {@link NdOption}, or {@code null} for an unknown or malformed option. - */ - public static NdOption parse(@NonNull ByteBuffer buf) { - if (buf.remaining() < STRUCT_SIZE) return null; - - // Peek the type without advancing the buffer. - byte type = buf.get(buf.position()); - int length = Byte.toUnsignedInt(buf.get(buf.position() + 1)); - if (length == 0) return null; - - switch (type) { - case StructNdOptPref64.TYPE: - return StructNdOptPref64.parse(buf); - - case StructNdOptRdnss.TYPE: - return StructNdOptRdnss.parse(buf); - - default: - int newPosition = Math.min(buf.limit(), buf.position() + length * 8); - buf.position(newPosition); - return UNKNOWN; - } - } - - void writeToByteBuffer(ByteBuffer buf) { - buf.put(type); - buf.put((byte) length); - } - - @Override - public String toString() { - return String.format("NdOption(%d, %d)", Byte.toUnsignedInt(type), length); - } - - public static final NdOption UNKNOWN = new NdOption((byte) 0, 0); -} diff --git a/common/device/com/android/net/module/util/netlink/NduseroptMessage.java b/common/device/com/android/net/module/util/netlink/NduseroptMessage.java deleted file mode 100644 index bdf574db..00000000 --- a/common/device/com/android/net/module/util/netlink/NduseroptMessage.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.net.module.util.netlink; - -import static android.system.OsConstants.AF_INET6; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * A NetlinkMessage subclass for RTM_NEWNDUSEROPT messages. - */ -public class NduseroptMessage extends NetlinkMessage { - public static final int STRUCT_SIZE = 16; - - static final int NDUSEROPT_SRCADDR = 1; - - /** The address family. Presumably always AF_INET6. */ - public final byte family; - /** - * The total length in bytes of the options that follow this structure. - * Actually a 16-bit unsigned integer. - */ - public final int opts_len; - /** The interface index on which the options were received. */ - public final int ifindex; - /** The ICMP type of the packet that contained the options. */ - public final byte icmp_type; - /** The ICMP code of the packet that contained the options. */ - public final byte icmp_code; - - /** - * ND option that was in this message. - * Even though the length field is called "opts_len", the kernel only ever sends one option per - * message. It is unlikely that this will ever change as it would break existing userspace code. - * But if it does, we can simply update this code, since userspace is typically newer than the - * kernel. - */ - @Nullable - public final NdOption option; - - /** The IP address that sent the packet containing the option. */ - public final InetAddress srcaddr; - - NduseroptMessage(@NonNull StructNlMsgHdr header, @NonNull ByteBuffer buf) - throws UnknownHostException { - super(header); - - // The structure itself. - buf.order(ByteOrder.nativeOrder()); // Restored in the finally clause inside parse(). - final int start = buf.position(); - family = buf.get(); - buf.get(); // Skip 1 byte of padding. - opts_len = Short.toUnsignedInt(buf.getShort()); - ifindex = buf.getInt(); - icmp_type = buf.get(); - icmp_code = buf.get(); - buf.position(buf.position() + 6); // Skip 6 bytes of padding. - - // The ND option. - // Ensure we don't read past opts_len even if the option length is invalid. - // Note that this check is not really necessary since if the option length is not valid, - // this struct won't be very useful to the caller. - // - // It's safer to pass the slice of original ByteBuffer to just parse the ND option field, - // although parsing ND option might throw exception or return null, it won't break the - // original ByteBuffer position. - buf.order(ByteOrder.BIG_ENDIAN); - try { - final ByteBuffer slice = buf.slice(); - slice.limit(opts_len); - option = NdOption.parse(slice); - } finally { - // Advance buffer position according to opts_len in the header. ND option length might - // be incorrect in the malformed packet. - int newPosition = start + STRUCT_SIZE + opts_len; - if (newPosition >= buf.limit()) { - throw new IllegalArgumentException("ND option extends past end of buffer"); - } - buf.position(newPosition); - } - - // The source address attribute. - StructNlAttr nla = StructNlAttr.parse(buf); - if (nla == null || nla.nla_type != NDUSEROPT_SRCADDR || nla.nla_value == null) { - throw new IllegalArgumentException("Invalid source address in ND useropt"); - } - if (family == AF_INET6) { - // InetAddress.getByAddress only looks at the ifindex if the address type needs one. - srcaddr = Inet6Address.getByAddress(null /* hostname */, nla.nla_value, ifindex); - } else { - srcaddr = InetAddress.getByAddress(nla.nla_value); - } - } - - /** - * Parses a StructNduseroptmsg from a {@link ByteBuffer}. - * - * @param header the netlink message header. - * @param buf The buffer from which to parse the option. The buffer's byte order must be - * {@link java.nio.ByteOrder#BIG_ENDIAN}. - * @return the parsed option, or {@code null} if the option could not be parsed successfully - * (for example, if it was truncated, or if the prefix length code was wrong). - */ - @Nullable - public static NduseroptMessage parse(@NonNull StructNlMsgHdr header, @NonNull ByteBuffer buf) { - if (buf == null || buf.remaining() < STRUCT_SIZE) return null; - ByteOrder oldOrder = buf.order(); - try { - return new NduseroptMessage(header, buf); - } catch (IllegalArgumentException | UnknownHostException | BufferUnderflowException e) { - // Not great, but better than throwing an exception that might crash the caller. - // Convention in this package is that null indicates that the option was truncated, so - // callers must already handle it. - return null; - } finally { - buf.order(oldOrder); - } - } - - @Override - public String toString() { - return String.format("Nduseroptmsg(%d, %d, %d, %d, %d, %s)", - family, opts_len, ifindex, Byte.toUnsignedInt(icmp_type), - Byte.toUnsignedInt(icmp_code), srcaddr.getHostAddress()); - } -} diff --git a/common/device/com/android/net/module/util/netlink/NetlinkConstants.java b/common/device/com/android/net/module/util/netlink/NetlinkConstants.java deleted file mode 100644 index 44c51d8a..00000000 --- a/common/device/com/android/net/module/util/netlink/NetlinkConstants.java +++ /dev/null @@ -1,283 +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 com.android.net.module.util.netlink; - -import android.system.OsConstants; - -import androidx.annotation.NonNull; - -import java.nio.ByteBuffer; - -/** - * Various constants and static helper methods for netlink communications. - * - * Values taken from: - * - * include/uapi/linux/netfilter/nfnetlink.h - * include/uapi/linux/netfilter/nfnetlink_conntrack.h - * include/uapi/linux/netlink.h - * include/uapi/linux/rtnetlink.h - * - * @hide - */ -public class NetlinkConstants { - private NetlinkConstants() {} - - public static final int NLA_ALIGNTO = 4; - /** - * Flag for dumping struct tcp_info. - * Corresponding to enum definition in external/strace/linux/inet_diag.h. - */ - public static final int INET_DIAG_MEMINFO = 1; - - public static final int SOCKDIAG_MSG_HEADER_SIZE = - StructNlMsgHdr.STRUCT_SIZE + StructInetDiagMsg.STRUCT_SIZE; - - /** - * Get the aligned length based on a Short type number. - */ - public static final int alignedLengthOf(short length) { - final int intLength = (int) length & 0xffff; - return alignedLengthOf(intLength); - } - - /** - * Get the aligned length based on a Integer type number. - */ - public static final int alignedLengthOf(int length) { - if (length <= 0) return 0; - return (((length + NLA_ALIGNTO - 1) / NLA_ALIGNTO) * NLA_ALIGNTO); - } - - /** - * Convert a address family type to a string. - */ - 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"; - if (family == OsConstants.AF_UNSPEC) return "AF_UNSPEC"; - return String.valueOf(family); - } - - /** - * Convert a protocol type to a string. - */ - 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); - } - - /** - * Convert a byte array to a hexadecimal string. - */ - public static String hexify(byte[] bytes) { - if (bytes == null) return "(null)"; - return toHexString(bytes, 0, bytes.length); - } - - /** - * Convert a {@link ByteBuffer} to a hexadecimal string. - */ - public static String hexify(ByteBuffer buffer) { - if (buffer == null) return "(null)"; - return 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; - - // Netfilter netlink message types are presented by two bytes: high byte subsystem and - // low byte operation. See the macro NFNL_SUBSYS_ID and NFNL_MSG_TYPE in - // include/uapi/linux/netfilter/nfnetlink.h - public static final short NFNL_SUBSYS_CTNETLINK = 1; - - public static final short IPCTNL_MSG_CT_NEW = 0; - public static final short IPCTNL_MSG_CT_GET = 1; - public static final short IPCTNL_MSG_CT_DELETE = 2; - public static final short IPCTNL_MSG_CT_GET_CTRZERO = 3; - public static final short IPCTNL_MSG_CT_GET_STATS_CPU = 4; - public static final short IPCTNL_MSG_CT_GET_STATS = 5; - public static final short IPCTNL_MSG_CT_GET_DYING = 6; - public static final short IPCTNL_MSG_CT_GET_UNCONFIRMED = 7; - - /* see include/uapi/linux/sock_diag.h */ - public static final short SOCK_DIAG_BY_FAMILY = 20; - public static final short SOCK_DESTROY = 21; - - // Netlink groups. - public static final int RTMGRP_LINK = 1; - public static final int RTMGRP_IPV4_IFADDR = 0x10; - public static final int RTMGRP_IPV6_IFADDR = 0x100; - public static final int RTMGRP_IPV6_ROUTE = 0x400; - public static final int RTNLGRP_ND_USEROPT = 20; - public static final int RTMGRP_ND_USEROPT = 1 << (RTNLGRP_ND_USEROPT - 1); - - // Device flags. - public static final int IFF_UP = 1 << 0; - public static final int IFF_LOWER_UP = 1 << 16; - - // Known values for struct rtmsg rtm_protocol. - public static final short RTPROT_KERNEL = 2; - public static final short RTPROT_RA = 9; - - // Known values for struct rtmsg rtm_scope. - public static final short RT_SCOPE_UNIVERSE = 0; - - // Known values for struct rtmsg rtm_type. - public static final short RTN_UNICAST = 1; - - // Known values for struct rtmsg rtm_flags. - public static final int RTM_F_CLONED = 0x200; - - /** - * Convert a netlink message type to a string for control message. - */ - @NonNull - private static String stringForCtlMsgType(short nlmType) { - switch (nlmType) { - case NLMSG_NOOP: return "NLMSG_NOOP"; - case NLMSG_ERROR: return "NLMSG_ERROR"; - case NLMSG_DONE: return "NLMSG_DONE"; - case NLMSG_OVERRUN: return "NLMSG_OVERRUN"; - default: return "unknown control message type: " + String.valueOf(nlmType); - } - } - - /** - * Convert a netlink message type to a string for NETLINK_ROUTE. - */ - @NonNull - private static String stringForRtMsgType(short nlmType) { - switch (nlmType) { - 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(nlmType); - } - } - - /** - * Convert a netlink message type to a string for NETLINK_INET_DIAG. - */ - @NonNull - private static String stringForInetDiagMsgType(short nlmType) { - switch (nlmType) { - case SOCK_DIAG_BY_FAMILY: return "SOCK_DIAG_BY_FAMILY"; - default: return "unknown SOCK_DIAG type: " + String.valueOf(nlmType); - } - } - - /** - * Convert a netlink message type to a string for NETLINK_NETFILTER. - */ - @NonNull - private static String stringForNfMsgType(short nlmType) { - final byte subsysId = (byte) (nlmType >> 8); - final byte msgType = (byte) nlmType; - switch (subsysId) { - case NFNL_SUBSYS_CTNETLINK: - switch (msgType) { - case IPCTNL_MSG_CT_NEW: return "IPCTNL_MSG_CT_NEW"; - case IPCTNL_MSG_CT_GET: return "IPCTNL_MSG_CT_GET"; - case IPCTNL_MSG_CT_DELETE: return "IPCTNL_MSG_CT_DELETE"; - case IPCTNL_MSG_CT_GET_CTRZERO: return "IPCTNL_MSG_CT_GET_CTRZERO"; - case IPCTNL_MSG_CT_GET_STATS_CPU: return "IPCTNL_MSG_CT_GET_STATS_CPU"; - case IPCTNL_MSG_CT_GET_STATS: return "IPCTNL_MSG_CT_GET_STATS"; - case IPCTNL_MSG_CT_GET_DYING: return "IPCTNL_MSG_CT_GET_DYING"; - case IPCTNL_MSG_CT_GET_UNCONFIRMED: return "IPCTNL_MSG_CT_GET_UNCONFIRMED"; - } - break; - } - return "unknown NETFILTER type: " + String.valueOf(nlmType); - } - - /** - * Convert a netlink message type to a string by netlink family. - */ - @NonNull - public static String stringForNlMsgType(short nlmType, int nlFamily) { - // Reserved control messages. The netlink family is ignored. - // See NLMSG_MIN_TYPE in include/uapi/linux/netlink.h. - if (nlmType <= NLMSG_MAX_RESERVED) return stringForCtlMsgType(nlmType); - - // Netlink family messages. The netlink family is required. Note that the reason for using - // if-statement is that switch-case can't be used because the OsConstants.NETLINK_* are - // not constant. - if (nlFamily == OsConstants.NETLINK_ROUTE) return stringForRtMsgType(nlmType); - if (nlFamily == OsConstants.NETLINK_INET_DIAG) return stringForInetDiagMsgType(nlmType); - if (nlFamily == OsConstants.NETLINK_NETFILTER) return stringForNfMsgType(nlmType); - - return "unknown type: " + String.valueOf(nlmType); - } - - private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F' }; - /** - * Convert a byte array to a hexadecimal string. - */ - public static String toHexString(byte[] array, int offset, int length) { - char[] buf = new char[length * 2]; - - int bufIndex = 0; - for (int i = offset; i < offset + length; i++) { - byte b = array[i]; - buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F]; - buf[bufIndex++] = HEX_DIGITS[b & 0x0F]; - } - - return new String(buf); - } -} diff --git a/common/device/com/android/net/module/util/netlink/NetlinkErrorMessage.java b/common/device/com/android/net/module/util/netlink/NetlinkErrorMessage.java deleted file mode 100644 index 48314323..00000000 --- a/common/device/com/android/net/module/util/netlink/NetlinkErrorMessage.java +++ /dev/null @@ -1,69 +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 com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.nio.ByteBuffer; - -/** - * A NetlinkMessage subclass for netlink error messages. - * - * @hide - */ -public class NetlinkErrorMessage extends NetlinkMessage { - - /** - * Parse a netlink error message from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the netlink error message. - * @return the parsed netlink error message, or {@code null} if the netlink error message - * could not be parsed successfully (for example, if it was truncated). - */ - @Nullable - public static NetlinkErrorMessage parse(@NonNull StructNlMsgHdr header, - @NonNull 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(@NonNull 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()) + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/NetlinkMessage.java b/common/device/com/android/net/module/util/netlink/NetlinkMessage.java deleted file mode 100644 index 9e1e26e7..00000000 --- a/common/device/com/android/net/module/util/netlink/NetlinkMessage.java +++ /dev/null @@ -1,171 +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 com.android.net.module.util.netlink; - -import android.system.OsConstants; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -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 static final String TAG = "NetlinkMessage"; - - /** - * Parsing netlink messages for reserved control message or specific netlink message. The - * netlink family is required for parsing specific netlink message. See man-pages/netlink. - */ - @Nullable - public static NetlinkMessage parse(@NonNull ByteBuffer byteBuffer, int nlFamily) { - final int startPosition = (byteBuffer != null) ? byteBuffer.position() : -1; - final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(byteBuffer); - if (nlmsghdr == null) { - return null; - } - - final int messageLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len); - final int payloadLength = messageLength - 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; - } - - // Reserved control messages. The netlink family is ignored. - // See NLMSG_MIN_TYPE in include/uapi/linux/netlink.h. - if (nlmsghdr.nlmsg_type <= NetlinkConstants.NLMSG_MAX_RESERVED) { - return parseCtlMessage(nlmsghdr, byteBuffer, payloadLength); - } - - // Netlink family messages. The netlink family is required. Note that the reason for using - // if-statement is that switch-case can't be used because the OsConstants.NETLINK_* are - // not constant. - final NetlinkMessage parsed; - if (nlFamily == OsConstants.NETLINK_ROUTE) { - parsed = parseRtMessage(nlmsghdr, byteBuffer); - } else if (nlFamily == OsConstants.NETLINK_INET_DIAG) { - parsed = parseInetDiagMessage(nlmsghdr, byteBuffer); - } else if (nlFamily == OsConstants.NETLINK_NETFILTER) { - parsed = parseNfMessage(nlmsghdr, byteBuffer); - } else { - parsed = null; - } - - // Advance to the end of the message, regardless of whether the parsing code consumed - // all of it or not. - byteBuffer.position(startPosition + messageLength); - - return parsed; - } - - @NonNull - protected final StructNlMsgHdr mHeader; - - public NetlinkMessage(@NonNull StructNlMsgHdr nlmsghdr) { - mHeader = nlmsghdr; - } - - @NonNull - public StructNlMsgHdr getHeader() { - return mHeader; - } - - @Override - public String toString() { - // The netlink family is not provided to StructNlMsgHdr#toString because NetlinkMessage - // doesn't store the information. So the netlink message type can't be transformed into - // a string by StructNlMsgHdr#toString and just keep as an integer. The specific message - // which inherits NetlinkMessage could override NetlinkMessage#toString and provide the - // specific netlink family to StructNlMsgHdr#toString. - return "NetlinkMessage{" + mHeader.toString() + "}"; - } - - @NonNull - private static NetlinkMessage parseCtlMessage(@NonNull StructNlMsgHdr nlmsghdr, - @NonNull ByteBuffer byteBuffer, int payloadLength) { - switch (nlmsghdr.nlmsg_type) { - case NetlinkConstants.NLMSG_ERROR: - return (NetlinkMessage) NetlinkErrorMessage.parse(nlmsghdr, byteBuffer); - default: { - // Other netlink control messages. Just parse the header for now, - // pretending the whole message was consumed. - byteBuffer.position(byteBuffer.position() + payloadLength); - return new NetlinkMessage(nlmsghdr); - } - } - } - - @Nullable - private static NetlinkMessage parseRtMessage(@NonNull StructNlMsgHdr nlmsghdr, - @NonNull ByteBuffer byteBuffer) { - switch (nlmsghdr.nlmsg_type) { - case NetlinkConstants.RTM_NEWLINK: - case NetlinkConstants.RTM_DELLINK: - return (NetlinkMessage) RtNetlinkLinkMessage.parse(nlmsghdr, byteBuffer); - case NetlinkConstants.RTM_NEWADDR: - case NetlinkConstants.RTM_DELADDR: - return (NetlinkMessage) RtNetlinkAddressMessage.parse(nlmsghdr, byteBuffer); - case NetlinkConstants.RTM_NEWROUTE: - case NetlinkConstants.RTM_DELROUTE: - return (NetlinkMessage) RtNetlinkRouteMessage.parse(nlmsghdr, byteBuffer); - case NetlinkConstants.RTM_NEWNEIGH: - case NetlinkConstants.RTM_DELNEIGH: - case NetlinkConstants.RTM_GETNEIGH: - return (NetlinkMessage) RtNetlinkNeighborMessage.parse(nlmsghdr, byteBuffer); - case NetlinkConstants.RTM_NEWNDUSEROPT: - return (NetlinkMessage) NduseroptMessage.parse(nlmsghdr, byteBuffer); - default: return null; - } - } - - @Nullable - private static NetlinkMessage parseInetDiagMessage(@NonNull StructNlMsgHdr nlmsghdr, - @NonNull ByteBuffer byteBuffer) { - switch (nlmsghdr.nlmsg_type) { - case NetlinkConstants.SOCK_DIAG_BY_FAMILY: - return (NetlinkMessage) InetDiagMessage.parse(nlmsghdr, byteBuffer); - default: return null; - } - } - - @Nullable - private static NetlinkMessage parseNfMessage(@NonNull StructNlMsgHdr nlmsghdr, - @NonNull ByteBuffer byteBuffer) { - switch (nlmsghdr.nlmsg_type) { - case NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8 - | NetlinkConstants.IPCTNL_MSG_CT_NEW: - case NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8 - | NetlinkConstants.IPCTNL_MSG_CT_DELETE: - return (NetlinkMessage) ConntrackMessage.parse(nlmsghdr, byteBuffer); - default: return null; - } - } -} diff --git a/common/device/com/android/net/module/util/netlink/NetlinkUtils.java b/common/device/com/android/net/module/util/netlink/NetlinkUtils.java deleted file mode 100644 index 33bd36d8..00000000 --- a/common/device/com/android/net/module/util/netlink/NetlinkUtils.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.net.module.util.netlink; - -import static android.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.NETLINK_INET_DIAG; -import static android.system.OsConstants.NETLINK_ROUTE; -import static android.system.OsConstants.SOCK_CLOEXEC; -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.OsConstants; -import android.system.StructTimeval; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.Inet6Address; -import java.net.SocketException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Objects; - -/** - * Utilities for netlink related class that may not be able to fit into a specific class. - * @hide - */ -public class NetlinkUtils { - private static final String TAG = "NetlinkUtils"; - /** Corresponds to enum from bionic/libc/include/netinet/tcp.h. */ - private static final int TCP_ESTABLISHED = 1; - private static final int TCP_SYN_SENT = 2; - private static final int TCP_SYN_RECV = 3; - - public static final int TCP_ALIVE_STATE_FILTER = - (1 << TCP_ESTABLISHED) | (1 << TCP_SYN_SENT) | (1 << TCP_SYN_RECV); - - public static final int UNKNOWN_MARK = 0xffffffff; - public static final int NULL_MASK = 0; - - // Initial mark value corresponds to the initValue in system/netd/include/Fwmark.h. - public static final int INIT_MARK_VALUE = 0; - // Corresponds to enum definition in bionic/libc/kernel/uapi/linux/inet_diag.h - public static final int INET_DIAG_INFO = 2; - public static final int INET_DIAG_MARK = 15; - - public static final long IO_TIMEOUT_MS = 300L; - - public static final int DEFAULT_RECV_BUFSIZE = 8 * 1024; - public static final int SOCKET_RECV_BUFSIZE = 64 * 1024; - - /** - * Return whether the input ByteBuffer contains enough remaining bytes for - * {@code StructNlMsgHdr}. - */ - public static boolean enoughBytesRemainForValidNlMsg(@NonNull final ByteBuffer bytes) { - return bytes.remaining() >= StructNlMsgHdr.STRUCT_SIZE; - } - - /** - * Parse netlink error message - * - * @param bytes byteBuffer to parse netlink error message - * @return NetlinkErrorMessage if bytes contains valid NetlinkErrorMessage, else {@code null} - */ - @Nullable - private static NetlinkErrorMessage parseNetlinkErrorMessage(ByteBuffer bytes) { - final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(bytes); - if (nlmsghdr == null || nlmsghdr.nlmsg_type != NetlinkConstants.NLMSG_ERROR) { - return null; - } - - final int messageLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len); - final int payloadLength = messageLength - StructNlMsgHdr.STRUCT_SIZE; - if (payloadLength < 0 || payloadLength > bytes.remaining()) { - // Malformed message or runt buffer. Pretend the buffer was consumed. - bytes.position(bytes.limit()); - return null; - } - - return NetlinkErrorMessage.parse(nlmsghdr, bytes); - } - - /** - * Receive netlink ack message and check error - * - * @param fd fd to read netlink message - */ - public static void receiveNetlinkAck(final FileDescriptor fd) - throws InterruptedIOException, ErrnoException { - final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT_MS); - // recvMessage() guaranteed to not return null if it did not throw. - final NetlinkErrorMessage response = parseNetlinkErrorMessage(bytes); - if (response != null && response.getNlMsgError() != null) { - final int errno = 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, "receiveNetlinkAck, 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, "receiveNetlinkAck, errmsg=" + errmsg); - throw new ErrnoException(errmsg, EPROTO); - } - } - - /** - * Send one netlink message to kernel via netlink socket. - * - * @param nlProto netlink protocol type. - * @param msg the raw bytes of netlink message to be sent. - */ - public static void sendOneShotKernelMessage(int nlProto, byte[] msg) throws ErrnoException { - final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage"; - final FileDescriptor fd = netlinkSocketForProto(nlProto); - - try { - connectSocketToNetlink(fd); - sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT_MS); - receiveNetlinkAck(fd); - } 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 - } - } - } - - /** - * Send an RTM_NEWADDR message to kernel to add or update an IPv6 address. - * - * @param ifIndex interface index. - * @param ip IPv6 address to be added. - * @param prefixlen IPv6 address prefix length. - * @param flags IPv6 address flags. - * @param scope IPv6 address scope. - * @param preferred The preferred lifetime of IPv6 address. - * @param valid The valid lifetime of IPv6 address. - */ - public static boolean sendRtmNewAddressRequest(int ifIndex, @NonNull final Inet6Address ip, - short prefixlen, int flags, byte scope, long preferred, long valid) { - Objects.requireNonNull(ip, "IPv6 address to be added should not be null."); - final byte[] msg = RtNetlinkAddressMessage.newRtmNewAddressMessage(1 /* seqNo*/, ip, - prefixlen, flags, scope, ifIndex, preferred, valid); - try { - NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, msg); - return true; - } catch (ErrnoException e) { - Log.e(TAG, "Fail to send RTM_NEWADDR to add " + ip.getHostAddress(), e); - return false; - } - } - - /** - * Send an RTM_DELADDR message to kernel to delete an IPv6 address. - * - * @param ifIndex interface index. - * @param ip IPv6 address to be deleted. - * @param prefixlen IPv6 address prefix length. - */ - public static boolean sendRtmDelAddressRequest(int ifIndex, final Inet6Address ip, - short prefixlen) { - Objects.requireNonNull(ip, "IPv6 address to be deleted should not be null."); - final byte[] msg = RtNetlinkAddressMessage.newRtmDelAddressMessage(1 /* seqNo*/, ip, - prefixlen, ifIndex); - try { - NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, msg); - return true; - } catch (ErrnoException e) { - Log.e(TAG, "Fail to send RTM_DELADDR to delete " + ip.getHostAddress(), e); - return false; - } - } - - /** - * Create netlink socket with the given netlink protocol type. - * - * @return fd the fileDescriptor of the socket. - * @throws ErrnoException if the FileDescriptor not connect to be created successfully - */ - public static FileDescriptor netlinkSocketForProto(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; - } - - /** - * Construct a netlink inet_diag socket. - */ - public static FileDescriptor createNetLinkInetDiagSocket() throws ErrnoException { - return Os.socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_INET_DIAG); - } - - /** - * Connect the given file descriptor to the Netlink interface to the kernel. - * - * The fd must be a SOCK_DGRAM socket : create it with {@link #netlinkSocketForProto} - * - * @throws ErrnoException if the {@code fd} could not connect to kernel successfully - * @throws SocketException if there is an error accessing a socket. - */ - public static void connectSocketToNetlink(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)); - - final ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize); - final 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. - * - * This waits at most |timeoutMs| milliseconds for the send to complete, will get the exception - * if it times out. - */ - 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); - } - - private static final long CLOCK_TICKS_PER_SECOND = Os.sysconf(OsConstants._SC_CLK_TCK); - - /** - * Convert the system time in clock ticks(clock_t type in times(), not in clock()) to - * milliseconds. times() clock_t ticks at the kernel's USER_HZ (100) while clock() clock_t - * ticks at CLOCKS_PER_SEC (1000000). - * - * See the NOTES on https://man7.org/linux/man-pages/man2/times.2.html for the difference - * of clock_t used in clock() and times(). - */ - public static long ticksToMilliSeconds(int intClockTicks) { - final long longClockTicks = intClockTicks & 0xffffffffL; - return (longClockTicks * 1000) / CLOCK_TICKS_PER_SECOND; - } - - private NetlinkUtils() {} -} diff --git a/common/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java b/common/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java deleted file mode 100644 index cbe0ab0e..00000000 --- a/common/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.net.module.util.netlink; - -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REPLACE; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; - -import android.system.OsConstants; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - -import com.android.net.module.util.HexDump; - -import java.net.Inet6Address; -import java.net.InetAddress; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Objects; - -/** - * A NetlinkMessage subclass for rtnetlink address messages. - * - * RtNetlinkAddressMessage.parse() must be called with a ByteBuffer that contains exactly one - * netlink message. - * - * see also: - * - * include/uapi/linux/rtnetlink.h - * - * @hide - */ -public class RtNetlinkAddressMessage extends NetlinkMessage { - public static final short IFA_ADDRESS = 1; - public static final short IFA_CACHEINFO = 6; - public static final short IFA_FLAGS = 8; - - private int mFlags; - @NonNull - private StructIfaddrMsg mIfaddrmsg; - @NonNull - private InetAddress mIpAddress; - @Nullable - private StructIfacacheInfo mIfacacheInfo; - - @VisibleForTesting - public RtNetlinkAddressMessage(@NonNull final StructNlMsgHdr header, - @NonNull final StructIfaddrMsg ifaddrMsg, - @NonNull final InetAddress ipAddress, - @Nullable final StructIfacacheInfo structIfacacheInfo, - int flags) { - super(header); - mIfaddrmsg = ifaddrMsg; - mIpAddress = ipAddress; - mIfacacheInfo = structIfacacheInfo; - mFlags = flags; - } - private RtNetlinkAddressMessage(@NonNull StructNlMsgHdr header) { - this(header, null, null, null, 0); - } - - public int getFlags() { - return mFlags; - } - - @NonNull - public StructIfaddrMsg getIfaddrHeader() { - return mIfaddrmsg; - } - - @NonNull - public InetAddress getIpAddress() { - return mIpAddress; - } - - @Nullable - public StructIfacacheInfo getIfacacheInfo() { - return mIfacacheInfo; - } - - /** - * Parse rtnetlink address message from {@link ByteBuffer}. This method must be called with a - * ByteBuffer that contains exactly one netlink message. - * - * @param header netlink message header. - * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. - */ - @Nullable - public static RtNetlinkAddressMessage parse(@NonNull final StructNlMsgHdr header, - @NonNull final ByteBuffer byteBuffer) { - final RtNetlinkAddressMessage addrMsg = new RtNetlinkAddressMessage(header); - - addrMsg.mIfaddrmsg = StructIfaddrMsg.parse(byteBuffer); - if (addrMsg.mIfaddrmsg == null) return null; - - // IFA_ADDRESS - final int baseOffset = byteBuffer.position(); - StructNlAttr nlAttr = StructNlAttr.findNextAttrOfType(IFA_ADDRESS, byteBuffer); - if (nlAttr == null) return null; - addrMsg.mIpAddress = nlAttr.getValueAsInetAddress(); - if (addrMsg.mIpAddress == null) return null; - - // IFA_CACHEINFO - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(IFA_CACHEINFO, byteBuffer); - if (nlAttr != null) { - addrMsg.mIfacacheInfo = StructIfacacheInfo.parse(nlAttr.getValueAsByteBuffer()); - } - - // The first 8 bits of flags are in the ifaddrmsg. - addrMsg.mFlags = addrMsg.mIfaddrmsg.flags; - // IFA_FLAGS. All the flags are in the IF_FLAGS attribute. This should always be present, - // and will overwrite the flags set above. - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(IFA_FLAGS, byteBuffer); - if (nlAttr == null) return null; - final Integer value = nlAttr.getValueAsInteger(); - if (value == null) return null; - addrMsg.mFlags = value; - - return addrMsg; - } - - /** - * Write a rtnetlink address message to {@link ByteBuffer}. - */ - @VisibleForTesting - protected void pack(ByteBuffer byteBuffer) { - getHeader().pack(byteBuffer); - mIfaddrmsg.pack(byteBuffer); - - final StructNlAttr address = new StructNlAttr(IFA_ADDRESS, mIpAddress); - address.pack(byteBuffer); - - if (mIfacacheInfo != null) { - final StructNlAttr cacheInfo = new StructNlAttr(IFA_CACHEINFO, - mIfacacheInfo.writeToBytes()); - cacheInfo.pack(byteBuffer); - } - - // If IFA_FLAGS attribute isn't present on the wire at parsing netlink message, it will - // still be packed to ByteBuffer even if the flag is 0. - final StructNlAttr flags = new StructNlAttr(IFA_FLAGS, mFlags); - flags.pack(byteBuffer); - } - - /** - * A convenience method to create a RTM_NEWADDR message. - */ - public static byte[] newRtmNewAddressMessage(int seqNo, @NonNull final InetAddress ip, - short prefixlen, int flags, byte scope, int ifIndex, long preferred, long valid) { - Objects.requireNonNull(ip, "IP address to be set via netlink message cannot be null"); - - final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr(); - nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWADDR; - nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_ACK; - nlmsghdr.nlmsg_seq = seqNo; - - final RtNetlinkAddressMessage msg = new RtNetlinkAddressMessage(nlmsghdr); - final byte family = - (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET); - // IFA_FLAGS attribute is always present within this method, just set flags from - // ifaddrmsg to 0. kernel will prefer the flags from IFA_FLAGS attribute. - msg.mIfaddrmsg = - new StructIfaddrMsg(family, prefixlen, (short) 0 /* flags */, scope, ifIndex); - msg.mIpAddress = ip; - msg.mIfacacheInfo = new StructIfacacheInfo(preferred, valid, 0 /* cstamp */, - 0 /* tstamp */); - msg.mFlags = flags; - - 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; - } - - /** - * A convenience method to create a RTM_DELADDR message. - */ - public static byte[] newRtmDelAddressMessage(int seqNo, @NonNull final InetAddress ip, - short prefixlen, int ifIndex) { - Objects.requireNonNull(ip, "IP address to be deleted via netlink message cannot be null"); - - final int ifaAddrAttrLength = NetlinkConstants.alignedLengthOf( - StructNlAttr.NLA_HEADERLEN + ip.getAddress().length); - final int length = StructNlMsgHdr.STRUCT_SIZE + StructIfaddrMsg.STRUCT_SIZE - + ifaAddrAttrLength; - 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_DELADDR; - nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - nlmsghdr.nlmsg_seq = seqNo; - nlmsghdr.pack(byteBuffer); - - final byte family = - (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET); - // Actually kernel ignores scope and flags(only deal with IFA_F_MANAGETEMPADDR, it - // indicates that all relevant IPv6 temporary addresses should be deleted as well when - // user space intends to delete a global IPv6 address with IFA_F_MANAGETEMPADDR), so - // far IFA_F_MANAGETEMPADDR flag isn't used in user space, it's fine to ignore it. - // However, we need to add IFA_FLAGS attribute in RTM_DELADDR if flags parsing should - // be supported in the future. - final StructIfaddrMsg ifaddrmsg = new StructIfaddrMsg(family, prefixlen, - (short) 0 /* flags */, (short) 0 /* scope */, ifIndex); - ifaddrmsg.pack(byteBuffer); - - final StructNlAttr address = new StructNlAttr(IFA_ADDRESS, ip); - address.pack(byteBuffer); - - return bytes; - } - - // This function helper gives the required buffer size for IFA_ADDRESS, IFA_CACHEINFO and - // IFA_FLAGS attributes encapsulation. However, that's not a mandatory requirement for all - // RtNetlinkAddressMessage, e.g. RTM_DELADDR sent from user space to kernel to delete an - // IP address only requires IFA_ADDRESS attribute. The caller should check if these attributes - // are necessary to carry when constructing a RtNetlinkAddressMessage. - private int getRequiredSpace() { - int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructIfaddrMsg.STRUCT_SIZE; - // IFA_ADDRESS attr - spaceRequired += NetlinkConstants.alignedLengthOf( - StructNlAttr.NLA_HEADERLEN + mIpAddress.getAddress().length); - // IFA_CACHEINFO attr - spaceRequired += NetlinkConstants.alignedLengthOf( - StructNlAttr.NLA_HEADERLEN + StructIfacacheInfo.STRUCT_SIZE); - // IFA_FLAGS "u32" attr - spaceRequired += StructNlAttr.NLA_HEADERLEN + 4; - return spaceRequired; - } - - @Override - public String toString() { - return "RtNetlinkAddressMessage{ " - + "nlmsghdr{" + mHeader.toString(OsConstants.NETLINK_ROUTE) + "}, " - + "Ifaddrmsg{" + mIfaddrmsg.toString() + "}, " - + "IP Address{" + mIpAddress.getHostAddress() + "}, " - + "IfacacheInfo{" + (mIfacacheInfo == null ? "" : mIfacacheInfo.toString()) + "}, " - + "Address Flags{" + HexDump.toHexString(mFlags) + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java b/common/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java deleted file mode 100644 index 92ec0c4e..00000000 --- a/common/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.net.module.util.netlink; - -import android.net.MacAddress; -import android.system.OsConstants; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - -import java.nio.ByteBuffer; - -/** - * A NetlinkMessage subclass for rtnetlink link messages. - * - * RtNetlinkLinkMessage.parse() must be called with a ByteBuffer that contains exactly one netlink - * message. - * - * see also: - * - * include/uapi/linux/rtnetlink.h - * - * @hide - */ -public class RtNetlinkLinkMessage extends NetlinkMessage { - public static final short IFLA_ADDRESS = 1; - public static final short IFLA_IFNAME = 3; - public static final short IFLA_MTU = 4; - - private int mMtu; - @NonNull - private StructIfinfoMsg mIfinfomsg; - @Nullable - private MacAddress mHardwareAddress; - @Nullable - private String mInterfaceName; - - private RtNetlinkLinkMessage(@NonNull StructNlMsgHdr header) { - super(header); - mIfinfomsg = null; - mMtu = 0; - mHardwareAddress = null; - mInterfaceName = null; - } - - public int getMtu() { - return mMtu; - } - - @NonNull - public StructIfinfoMsg getIfinfoHeader() { - return mIfinfomsg; - } - - @Nullable - public MacAddress getHardwareAddress() { - return mHardwareAddress; - } - - @Nullable - public String getInterfaceName() { - return mInterfaceName; - } - - /** - * Parse rtnetlink link message from {@link ByteBuffer}. This method must be called with a - * ByteBuffer that contains exactly one netlink message. - * - * @param header netlink message header. - * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. - */ - @Nullable - public static RtNetlinkLinkMessage parse(@NonNull final StructNlMsgHdr header, - @NonNull final ByteBuffer byteBuffer) { - final RtNetlinkLinkMessage linkMsg = new RtNetlinkLinkMessage(header); - - linkMsg.mIfinfomsg = StructIfinfoMsg.parse(byteBuffer); - if (linkMsg.mIfinfomsg == null) return null; - - // IFLA_MTU - final int baseOffset = byteBuffer.position(); - StructNlAttr nlAttr = StructNlAttr.findNextAttrOfType(IFLA_MTU, byteBuffer); - if (nlAttr != null) { - linkMsg.mMtu = nlAttr.getValueAsInt(0 /* default value */); - } - - // IFLA_ADDRESS - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(IFLA_ADDRESS, byteBuffer); - if (nlAttr != null) { - linkMsg.mHardwareAddress = nlAttr.getValueAsMacAddress(); - } - - // IFLA_IFNAME - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(IFLA_IFNAME, byteBuffer); - if (nlAttr != null) { - linkMsg.mInterfaceName = nlAttr.getValueAsString(); - } - - return linkMsg; - } - - /** - * Write a rtnetlink link message to {@link ByteBuffer}. - */ - @VisibleForTesting - protected void pack(ByteBuffer byteBuffer) { - getHeader().pack(byteBuffer); - mIfinfomsg.pack(byteBuffer); - - if (mMtu != 0) { - final StructNlAttr mtu = new StructNlAttr(IFLA_MTU, mMtu); - mtu.pack(byteBuffer); - } - if (mHardwareAddress != null) { - final StructNlAttr hardwareAddress = new StructNlAttr(IFLA_ADDRESS, mHardwareAddress); - hardwareAddress.pack(byteBuffer); - } - if (mInterfaceName != null) { - final StructNlAttr ifname = new StructNlAttr(IFLA_IFNAME, mInterfaceName); - ifname.pack(byteBuffer); - } - } - - @Override - public String toString() { - return "RtNetlinkLinkMessage{ " - + "nlmsghdr{" + mHeader.toString(OsConstants.NETLINK_ROUTE) + "}, " - + "Ifinfomsg{" + mIfinfomsg.toString() + "}, " - + "Hardware Address{" + mHardwareAddress + "}, " - + "MTU{" + mMtu + "}, " - + "Ifname{" + mInterfaceName + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/RtNetlinkNeighborMessage.java b/common/device/com/android/net/module/util/netlink/RtNetlinkNeighborMessage.java deleted file mode 100644 index 4a090151..00000000 --- a/common/device/com/android/net/module/util/netlink/RtNetlinkNeighborMessage.java +++ /dev/null @@ -1,242 +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 com.android.net.module.util.netlink; - -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REPLACE; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; - -import android.system.OsConstants; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.net.Inet6Address; -import java.net.InetAddress; -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; - - /** - * Parse routing socket netlink neighbor message from ByteBuffer. - * - * @param header netlink message header. - * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. - */ - @Nullable - public static RtNetlinkNeighborMessage parse(@NonNull StructNlMsgHdr header, - @NonNull 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 = StructNlAttr.findNextAttrOfType(NDA_DST, byteBuffer); - if (nlAttr != null) { - neighMsg.mDestination = nlAttr.getValueAsInetAddress(); - } - - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(NDA_LLADDR, byteBuffer); - if (nlAttr != null) { - neighMsg.mLinkLayerAddr = nlAttr.nla_value; - } - - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(NDA_PROBES, byteBuffer); - if (nlAttr != null) { - neighMsg.mNumProbes = nlAttr.getValueAsInt(0); - } - - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.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(@NonNull 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; - } - - private 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); - } - - /** - * Write a neighbor discovery netlink message to {@link 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(OsConstants.NETLINK_ROUTE)) + "}, " - + "ndmsg{" + (mNdmsg == null ? "" : mNdmsg.toString()) + "}, " - + "destination{" + ipLiteral + "} " - + "linklayeraddr{" + NetlinkConstants.hexify(mLinkLayerAddr) + "} " - + "probes{" + mNumProbes + "} " - + "cacheinfo{" + (mCacheInfo == null ? "" : mCacheInfo.toString()) + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java b/common/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java deleted file mode 100644 index 9acac69c..00000000 --- a/common/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.net.module.util.netlink; - -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; - -import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY; -import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ANY; - -import android.annotation.SuppressLint; -import android.net.IpPrefix; -import android.system.OsConstants; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.nio.ByteBuffer; - -/** - * A NetlinkMessage subclass for rtnetlink route messages. - * - * RtNetlinkRouteMessage.parse() must be called with a ByteBuffer that contains exactly one - * netlink message. - * - * see also: - * - * include/uapi/linux/rtnetlink.h - * - * @hide - */ -public class RtNetlinkRouteMessage extends NetlinkMessage { - public static final short RTA_DST = 1; - public static final short RTA_OIF = 4; - public static final short RTA_GATEWAY = 5; - public static final short RTA_CACHEINFO = 12; - - private int mIfindex; - @NonNull - private StructRtMsg mRtmsg; - @NonNull - private IpPrefix mDestination; - @Nullable - private InetAddress mGateway; - @Nullable - private StructRtaCacheInfo mRtaCacheInfo; - - private RtNetlinkRouteMessage(StructNlMsgHdr header) { - super(header); - mRtmsg = null; - mDestination = null; - mGateway = null; - mIfindex = 0; - mRtaCacheInfo = null; - } - - public int getInterfaceIndex() { - return mIfindex; - } - - @NonNull - public StructRtMsg getRtMsgHeader() { - return mRtmsg; - } - - @NonNull - public IpPrefix getDestination() { - return mDestination; - } - - @Nullable - public InetAddress getGateway() { - return mGateway; - } - - @Nullable - public StructRtaCacheInfo getRtaCacheInfo() { - return mRtaCacheInfo; - } - - /** - * Check whether the address families of destination and gateway match rtm_family in - * StructRtmsg. - * - * For example, IPv4-mapped IPv6 addresses as an IPv6 address will be always converted to IPv4 - * address, that's incorrect when upper layer creates a new {@link RouteInfo} class instance - * for IPv6 route with the converted IPv4 gateway. - */ - private static boolean matchRouteAddressFamily(@NonNull final InetAddress address, - int family) { - return ((address instanceof Inet4Address) && (family == AF_INET)) - || ((address instanceof Inet6Address) && (family == AF_INET6)); - } - - /** - * Parse rtnetlink route message from {@link ByteBuffer}. This method must be called with a - * ByteBuffer that contains exactly one netlink message. - * - * @param header netlink message header. - * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. - */ - @SuppressLint("NewApi") - @Nullable - public static RtNetlinkRouteMessage parse(@NonNull final StructNlMsgHdr header, - @NonNull final ByteBuffer byteBuffer) { - final RtNetlinkRouteMessage routeMsg = new RtNetlinkRouteMessage(header); - - routeMsg.mRtmsg = StructRtMsg.parse(byteBuffer); - if (routeMsg.mRtmsg == null) return null; - int rtmFamily = routeMsg.mRtmsg.family; - - // RTA_DST - final int baseOffset = byteBuffer.position(); - StructNlAttr nlAttr = StructNlAttr.findNextAttrOfType(RTA_DST, byteBuffer); - if (nlAttr != null) { - final InetAddress destination = nlAttr.getValueAsInetAddress(); - // If the RTA_DST attribute is malformed, return null. - if (destination == null) return null; - // If the address family of destination doesn't match rtm_family, return null. - if (!matchRouteAddressFamily(destination, rtmFamily)) return null; - routeMsg.mDestination = new IpPrefix(destination, routeMsg.mRtmsg.dstLen); - } else if (rtmFamily == AF_INET) { - routeMsg.mDestination = new IpPrefix(IPV4_ADDR_ANY, 0); - } else if (rtmFamily == AF_INET6) { - routeMsg.mDestination = new IpPrefix(IPV6_ADDR_ANY, 0); - } else { - return null; - } - - // RTA_GATEWAY - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(RTA_GATEWAY, byteBuffer); - if (nlAttr != null) { - routeMsg.mGateway = nlAttr.getValueAsInetAddress(); - // If the RTA_GATEWAY attribute is malformed, return null. - if (routeMsg.mGateway == null) return null; - // If the address family of gateway doesn't match rtm_family, return null. - if (!matchRouteAddressFamily(routeMsg.mGateway, rtmFamily)) return null; - } - - // RTA_OIF - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(RTA_OIF, byteBuffer); - if (nlAttr != null) { - // Any callers that deal with interface names are responsible for converting - // the interface index to a name themselves. This may not succeed or may be - // incorrect, because the interface might have been deleted, or even deleted - // and re-added with a different index, since the netlink message was sent. - routeMsg.mIfindex = nlAttr.getValueAsInt(0 /* 0 isn't a valid ifindex */); - } - - // RTA_CACHEINFO - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(RTA_CACHEINFO, byteBuffer); - if (nlAttr != null) { - routeMsg.mRtaCacheInfo = StructRtaCacheInfo.parse(nlAttr.getValueAsByteBuffer()); - } - - return routeMsg; - } - - /** - * Write a rtnetlink address message to {@link ByteBuffer}. - */ - @VisibleForTesting - protected void pack(ByteBuffer byteBuffer) { - getHeader().pack(byteBuffer); - mRtmsg.pack(byteBuffer); - - final StructNlAttr destination = new StructNlAttr(RTA_DST, mDestination.getAddress()); - destination.pack(byteBuffer); - - if (mGateway != null) { - final StructNlAttr gateway = new StructNlAttr(RTA_GATEWAY, mGateway.getAddress()); - gateway.pack(byteBuffer); - } - if (mIfindex != 0) { - final StructNlAttr ifindex = new StructNlAttr(RTA_OIF, mIfindex); - ifindex.pack(byteBuffer); - } - if (mRtaCacheInfo != null) { - final StructNlAttr cacheInfo = new StructNlAttr(RTA_CACHEINFO, - mRtaCacheInfo.writeToBytes()); - cacheInfo.pack(byteBuffer); - } - } - - @Override - public String toString() { - return "RtNetlinkRouteMessage{ " - + "nlmsghdr{" + mHeader.toString(OsConstants.NETLINK_ROUTE) + "}, " - + "Rtmsg{" + mRtmsg.toString() + "}, " - + "destination{" + mDestination.getAddress().getHostAddress() + "}, " - + "gateway{" + (mGateway == null ? "" : mGateway.getHostAddress()) + "}, " - + "ifindex{" + mIfindex + "}, " - + "rta_cacheinfo{" + (mRtaCacheInfo == null ? "" : mRtaCacheInfo.toString()) + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructIfacacheInfo.java b/common/device/com/android/net/module/util/netlink/StructIfacacheInfo.java deleted file mode 100644 index 360f56d2..00000000 --- a/common/device/com/android/net/module/util/netlink/StructIfacacheInfo.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; - -/** - * struct ifa_cacheinfo - * - * see also: - * - * include/uapi/linux/if_addr.h - * - * @hide - */ -public class StructIfacacheInfo extends Struct { - // Already aligned. - public static final int STRUCT_SIZE = 16; - - @Field(order = 0, type = Type.U32) - public final long preferred; - @Field(order = 1, type = Type.U32) - public final long valid; - @Field(order = 2, type = Type.U32) - public final long cstamp; // created timestamp, hundredths of seconds. - @Field(order = 3, type = Type.U32) - public final long tstamp; // updated timestamp, hundredths of seconds. - - StructIfacacheInfo(long preferred, long valid, long cstamp, long tstamp) { - this.preferred = preferred; - this.valid = valid; - this.cstamp = cstamp; - this.tstamp = tstamp; - } - - /** - * Parse an ifa_cacheinfo struct from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the ifa_cacheinfo. - * @return the parsed ifa_cacheinfo struct, or {@code null} if the ifa_cacheinfo struct - * could not be parsed successfully (for example, if it was truncated). - */ - @Nullable - public static StructIfacacheInfo parse(@NonNull final ByteBuffer byteBuffer) { - if (byteBuffer.remaining() < STRUCT_SIZE) return null; - - // The ByteOrder must already have been set to native order. - return Struct.parse(StructIfacacheInfo.class, byteBuffer); - } - - /** - * Write an ifa_cacheinfo struct to {@link ByteBuffer}. - */ - public void pack(@NonNull final ByteBuffer byteBuffer) { - // The ByteOrder must already have been set to native order. - this.writeToByteBuffer(byteBuffer); - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructIfaddrMsg.java b/common/device/com/android/net/module/util/netlink/StructIfaddrMsg.java deleted file mode 100644 index f9781a7b..00000000 --- a/common/device/com/android/net/module/util/netlink/StructIfaddrMsg.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; - -/** - * struct ifaddrmsg - * - * see also: - * - * include/uapi/linux/if_addr.h - * - * @hide - */ -public class StructIfaddrMsg extends Struct { - // Already aligned. - public static final int STRUCT_SIZE = 8; - - @Field(order = 0, type = Type.U8) - public final short family; - @Field(order = 1, type = Type.U8) - public final short prefixLen; - @Field(order = 2, type = Type.U8) - public final short flags; - @Field(order = 3, type = Type.U8) - public final short scope; - @Field(order = 4, type = Type.S32) - public final int index; - - public StructIfaddrMsg(short family, short prefixLen, short flags, short scope, int index) { - this.family = family; - this.prefixLen = prefixLen; - this.flags = flags; - this.scope = scope; - this.index = index; - } - - /** - * Parse an ifaddrmsg struct from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the ifaddrmsg. - * @return the parsed ifaddrmsg struct, or {@code null} if the ifaddrmsg struct - * could not be parsed successfully (for example, if it was truncated). - */ - @Nullable - public static StructIfaddrMsg parse(@NonNull final ByteBuffer byteBuffer) { - if (byteBuffer.remaining() < STRUCT_SIZE) return null; - - // The ByteOrder must already have been set to native order. - return Struct.parse(StructIfaddrMsg.class, byteBuffer); - } - - /** - * Write an ifaddrmsg struct to {@link ByteBuffer}. - */ - public void pack(@NonNull final ByteBuffer byteBuffer) { - // The ByteOrder must already have been set to native order. - this.writeToByteBuffer(byteBuffer); - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructIfinfoMsg.java b/common/device/com/android/net/module/util/netlink/StructIfinfoMsg.java deleted file mode 100644 index 02d1574b..00000000 --- a/common/device/com/android/net/module/util/netlink/StructIfinfoMsg.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; - -/** - * struct ifinfomsg - * - * see also: - * - * include/uapi/linux/rtnetlink.h - * - * @hide - */ -public class StructIfinfoMsg extends Struct { - // Already aligned. - public static final int STRUCT_SIZE = 16; - - @Field(order = 0, type = Type.U8, padding = 1) - public final short family; - @Field(order = 1, type = Type.U16) - public final int type; - @Field(order = 2, type = Type.S32) - public final int index; - @Field(order = 3, type = Type.U32) - public final long flags; - @Field(order = 4, type = Type.U32) - public final long change; - - StructIfinfoMsg(short family, int type, int index, long flags, long change) { - this.family = family; - this.type = type; - this.index = index; - this.flags = flags; - this.change = change; - } - - /** - * Parse an ifinfomsg struct from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the ifinfomsg. - * @return the parsed ifinfomsg struct, or {@code null} if the ifinfomsg struct - * could not be parsed successfully (for example, if it was truncated). - */ - @Nullable - public static StructIfinfoMsg parse(@NonNull final ByteBuffer byteBuffer) { - if (byteBuffer.remaining() < STRUCT_SIZE) return null; - - // The ByteOrder must already have been set to native order. - return Struct.parse(StructIfinfoMsg.class, byteBuffer); - } - - /** - * Write an ifinfomsg struct to {@link ByteBuffer}. - */ - public void pack(@NonNull final ByteBuffer byteBuffer) { - // The ByteOrder must already have been set to native order. - this.writeToByteBuffer(byteBuffer); - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructInetDiagMsg.java b/common/device/com/android/net/module/util/netlink/StructInetDiagMsg.java deleted file mode 100644 index cbd895d6..00000000 --- a/common/device/com/android/net/module/util/netlink/StructInetDiagMsg.java +++ /dev/null @@ -1,103 +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 com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.nio.ByteBuffer; - -/** - * 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; - public short idiag_family; - public short idiag_state; - public short idiag_timer; - public short idiag_retrans; - @NonNull - public StructInetDiagSockId id; - public long idiag_expires; - public long idiag_rqueue; - public long idiag_wqueue; - // Use int for uid since other code use int for uid and uid fits to int - public int idiag_uid; - public long idiag_inode; - - private static short unsignedByte(byte b) { - return (short) (b & 0xFF); - } - - /** - * Parse inet diag netlink message from buffer. - */ - @Nullable - public static StructInetDiagMsg parse(@NonNull ByteBuffer byteBuffer) { - if (byteBuffer.remaining() < STRUCT_SIZE) { - return null; - } - StructInetDiagMsg struct = new StructInetDiagMsg(); - struct.idiag_family = unsignedByte(byteBuffer.get()); - struct.idiag_state = unsignedByte(byteBuffer.get()); - struct.idiag_timer = unsignedByte(byteBuffer.get()); - struct.idiag_retrans = unsignedByte(byteBuffer.get()); - struct.id = StructInetDiagSockId.parse(byteBuffer, struct.idiag_family); - if (struct.id == null) { - return null; - } - struct.idiag_expires = Integer.toUnsignedLong(byteBuffer.getInt()); - struct.idiag_rqueue = Integer.toUnsignedLong(byteBuffer.getInt()); - struct.idiag_wqueue = Integer.toUnsignedLong(byteBuffer.getInt()); - struct.idiag_uid = byteBuffer.getInt(); - struct.idiag_inode = Integer.toUnsignedLong(byteBuffer.getInt()); - return struct; - } - - @Override - public String toString() { - return "StructInetDiagMsg{ " - + "idiag_family{" + idiag_family + "}, " - + "idiag_state{" + idiag_state + "}, " - + "idiag_timer{" + idiag_timer + "}, " - + "idiag_retrans{" + idiag_retrans + "}, " - + "id{" + id + "}, " - + "idiag_expires{" + idiag_expires + "}, " - + "idiag_rqueue{" + idiag_rqueue + "}, " - + "idiag_wqueue{" + idiag_wqueue + "}, " - + "idiag_uid{" + idiag_uid + "}, " - + "idiag_inode{" + idiag_inode + "}, " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java b/common/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java deleted file mode 100644 index 3b47008a..00000000 --- a/common/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java +++ /dev/null @@ -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 com.android.net.module.util.netlink; - -import androidx.annotation.Nullable; - -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, @Nullable StructInetDiagSockId id, int family, int pad, - int extension, int state) { - mSdiagFamily = (byte) family; - mSdiagProtocol = (byte) protocol; - mId = id; - mPad = (byte) pad; - mIdiagExt = (byte) extension; - mState = state; - } - - /** - * Write the int diag request v2 message to ByteBuffer. - */ - 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") - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructInetDiagSockId.java b/common/device/com/android/net/module/util/netlink/StructInetDiagSockId.java deleted file mode 100644 index dd85934c..00000000 --- a/common/device/com/android/net/module/util/netlink/StructInetDiagSockId.java +++ /dev/null @@ -1,174 +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 com.android.net.module.util.netlink; - -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; - -import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_LEN; -import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_LEN; - -import static java.nio.ByteOrder.BIG_ENDIAN; - -import android.util.Log; - -import androidx.annotation.Nullable; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.UnknownHostException; -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 { - private static final String TAG = StructInetDiagSockId.class.getSimpleName(); - public static final int STRUCT_SIZE = 48; - - private static final long INET_DIAG_NOCOOKIE = ~0L; - private static final byte[] IPV4_PADDING = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - - public final InetSocketAddress locSocketAddress; - public final InetSocketAddress remSocketAddress; - public final int ifIndex; - public final long cookie; - - public StructInetDiagSockId(InetSocketAddress loc, InetSocketAddress rem) { - this(loc, rem, 0 /* ifIndex */, INET_DIAG_NOCOOKIE); - } - - public StructInetDiagSockId(InetSocketAddress loc, InetSocketAddress rem, - int ifIndex, long cookie) { - this.locSocketAddress = loc; - this.remSocketAddress = rem; - this.ifIndex = ifIndex; - this.cookie = cookie; - } - - /** - * Parse inet diag socket id from buffer. - */ - @Nullable - public static StructInetDiagSockId parse(final ByteBuffer byteBuffer, final short family) { - if (byteBuffer.remaining() < STRUCT_SIZE) { - return null; - } - - byteBuffer.order(BIG_ENDIAN); - final int srcPort = Short.toUnsignedInt(byteBuffer.getShort()); - final int dstPort = Short.toUnsignedInt(byteBuffer.getShort()); - - final InetAddress srcAddr; - final InetAddress dstAddr; - if (family == AF_INET) { - final byte[] srcAddrByte = new byte[IPV4_ADDR_LEN]; - final byte[] dstAddrByte = new byte[IPV4_ADDR_LEN]; - byteBuffer.get(srcAddrByte); - // Address always uses IPV6_ADDR_LEN in the buffer. So if the address is IPv4, position - // needs to be advanced to the next field. - byteBuffer.position(byteBuffer.position() + (IPV6_ADDR_LEN - IPV4_ADDR_LEN)); - byteBuffer.get(dstAddrByte); - byteBuffer.position(byteBuffer.position() + (IPV6_ADDR_LEN - IPV4_ADDR_LEN)); - try { - srcAddr = Inet4Address.getByAddress(srcAddrByte); - dstAddr = Inet4Address.getByAddress(dstAddrByte); - } catch (UnknownHostException e) { - Log.wtf(TAG, "Failed to parse address: " + e); - return null; - } - } else if (family == AF_INET6) { - final byte[] srcAddrByte = new byte[IPV6_ADDR_LEN]; - final byte[] dstAddrByte = new byte[IPV6_ADDR_LEN]; - byteBuffer.get(srcAddrByte); - byteBuffer.get(dstAddrByte); - try { - // Using Inet6Address.getByAddress to be consistent with idiag_family field since - // InetAddress.getByAddress returns Inet4Address if the address is v4-mapped v6 - // address. - srcAddr = Inet6Address.getByAddress( - null /* host */, srcAddrByte, -1 /* scope_id */); - dstAddr = Inet6Address.getByAddress( - null /* host */, dstAddrByte, -1 /* scope_id */); - } catch (UnknownHostException e) { - Log.wtf(TAG, "Failed to parse address: " + e); - return null; - } - } else { - Log.wtf(TAG, "Invalid address family: " + family); - return null; - } - - final InetSocketAddress srcSocketAddr = new InetSocketAddress(srcAddr, srcPort); - final InetSocketAddress dstSocketAddr = new InetSocketAddress(dstAddr, dstPort); - - byteBuffer.order(ByteOrder.nativeOrder()); - final int ifIndex = byteBuffer.getInt(); - final long cookie = byteBuffer.getLong(); - return new StructInetDiagSockId(srcSocketAddr, dstSocketAddr, ifIndex, cookie); - } - - /** - * Write inet diag socket id message to ByteBuffer in big endian. - */ - public void pack(ByteBuffer byteBuffer) { - byteBuffer.order(BIG_ENDIAN); - byteBuffer.putShort((short) locSocketAddress.getPort()); - byteBuffer.putShort((short) remSocketAddress.getPort()); - byteBuffer.put(locSocketAddress.getAddress().getAddress()); - if (locSocketAddress.getAddress() instanceof Inet4Address) { - byteBuffer.put(IPV4_PADDING); - } - byteBuffer.put(remSocketAddress.getAddress().getAddress()); - if (remSocketAddress.getAddress() instanceof Inet4Address) { - byteBuffer.put(IPV4_PADDING); - } - byteBuffer.order(ByteOrder.nativeOrder()); - byteBuffer.putInt(ifIndex); - byteBuffer.putLong(cookie); - } - - @Override - public String toString() { - return "StructInetDiagSockId{ " - + "idiag_sport{" + locSocketAddress.getPort() + "}, " - + "idiag_dport{" + remSocketAddress.getPort() + "}, " - + "idiag_src{" + locSocketAddress.getAddress().getHostAddress() + "}, " - + "idiag_dst{" + remSocketAddress.getAddress().getHostAddress() + "}, " - + "idiag_if{" + ifIndex + "}, " - + "idiag_cookie{" - + (cookie == INET_DIAG_NOCOOKIE ? "INET_DIAG_NOCOOKIE" : cookie) + "}" - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructNdMsg.java b/common/device/com/android/net/module/util/netlink/StructNdMsg.java deleted file mode 100644 index 53ce8991..00000000 --- a/common/device/com/android/net/module/util/netlink/StructNdMsg.java +++ /dev/null @@ -1,198 +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 com.android.net.module.util.netlink; - -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; - - /** - * Convert neighbor cache entry state integer to string. - */ - 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); - } - } - - /** - * Check whether a neighbor is connected or not. - */ - public static boolean isNudStateConnected(short nudState) { - return ((nudState & (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE)) != 0); - } - - /** - * Check whether a neighbor is in the valid NUD state or not. - */ - 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; - - private 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; - } - - /** - * Parse a neighbor discovery netlink message header from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the nd netlink message header. - * @return the parsed nd netlink message header, or {@code null} if the nd netlink message - * header could not be parsed successfully (for example, if it was truncated). - */ - 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; - } - - /** - * Write the neighbor discovery message header to {@link ByteBuffer}. - */ - 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); - } - - /** - * Check whether a neighbor is connected or not. - */ - public boolean nudConnected() { - return isNudStateConnected(ndm_state); - } - - /** - * Check whether a neighbor is in the valid NUD state or not. - */ - 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 + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructNdOptPref64.java b/common/device/com/android/net/module/util/netlink/StructNdOptPref64.java deleted file mode 100644 index 82263466..00000000 --- a/common/device/com/android/net/module/util/netlink/StructNdOptPref64.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.net.module.util.netlink; - -import android.annotation.SuppressLint; -import android.net.IpPrefix; -import android.util.Log; - -import androidx.annotation.NonNull; - -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.util.Objects; - -/** - * The PREF64 router advertisement option. RFC 8781. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Length | Scaled Lifetime | PLC | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * + + - * | Highest 96 bits of the Prefix | - * + + - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - */ -public class StructNdOptPref64 extends NdOption { - public static final int STRUCT_SIZE = 16; - public static final int TYPE = 38; - public static final byte LENGTH = 2; - - private static final String TAG = StructNdOptPref64.class.getSimpleName(); - - /** - * How many seconds the prefix is expected to remain valid. - * Valid values are from 0 to 65528 in multiples of 8. - */ - public final int lifetime; - /** The NAT64 prefix. */ - @NonNull public final IpPrefix prefix; - - static int plcToPrefixLength(int plc) { - switch (plc) { - case 0: return 96; - case 1: return 64; - case 2: return 56; - case 3: return 48; - case 4: return 40; - case 5: return 32; - default: - throw new IllegalArgumentException("Invalid prefix length code " + plc); - } - } - - static int prefixLengthToPlc(int prefixLength) { - switch (prefixLength) { - case 96: return 0; - case 64: return 1; - case 56: return 2; - case 48: return 3; - case 40: return 4; - case 32: return 5; - default: - throw new IllegalArgumentException("Invalid prefix length " + prefixLength); - } - } - - /** - * Returns the 2-byte "scaled lifetime and prefix length code" field: 13-bit lifetime, 3-bit PLC - */ - static short getScaledLifetimePlc(int lifetime, int prefixLengthCode) { - return (short) ((lifetime & 0xfff8) | (prefixLengthCode & 0x7)); - } - - public StructNdOptPref64(@NonNull IpPrefix prefix, int lifetime) { - super((byte) TYPE, LENGTH); - - Objects.requireNonNull(prefix, "prefix must not be null"); - if (!(prefix.getAddress() instanceof Inet6Address)) { - throw new IllegalArgumentException("Must be an IPv6 prefix: " + prefix); - } - prefixLengthToPlc(prefix.getPrefixLength()); // Throw if the prefix length is invalid. - this.prefix = prefix; - - if (lifetime < 0 || lifetime > 0xfff8) { - throw new IllegalArgumentException("Invalid lifetime " + lifetime); - } - this.lifetime = lifetime & 0xfff8; - } - - @SuppressLint("NewApi") - private StructNdOptPref64(@NonNull ByteBuffer buf) { - super(buf.get(), Byte.toUnsignedInt(buf.get())); - if (type != TYPE) throw new IllegalArgumentException("Invalid type " + type); - if (length != LENGTH) throw new IllegalArgumentException("Invalid length " + length); - - int scaledLifetimePlc = Short.toUnsignedInt(buf.getShort()); - lifetime = scaledLifetimePlc & 0xfff8; - - byte[] addressBytes = new byte[16]; - buf.get(addressBytes, 0, 12); - InetAddress addr; - try { - addr = InetAddress.getByAddress(addressBytes); - } catch (UnknownHostException e) { - throw new AssertionError("16-byte array not valid InetAddress?"); - } - prefix = new IpPrefix(addr, plcToPrefixLength(scaledLifetimePlc & 7)); - } - - /** - * Parses an option from a {@link ByteBuffer}. - * - * @param buf The buffer from which to parse the option. The buffer's byte order must be - * {@link java.nio.ByteOrder#BIG_ENDIAN}. - * @return the parsed option, or {@code null} if the option could not be parsed successfully - * (for example, if it was truncated, or if the prefix length code was wrong). - */ - public static StructNdOptPref64 parse(@NonNull ByteBuffer buf) { - if (buf.remaining() < STRUCT_SIZE) return null; - try { - return new StructNdOptPref64(buf); - } catch (IllegalArgumentException e) { - // Not great, but better than throwing an exception that might crash the caller. - // Convention in this package is that null indicates that the option was truncated, so - // callers must already handle it. - Log.d(TAG, "Invalid PREF64 option: " + e); - return null; - } - } - - protected void writeToByteBuffer(ByteBuffer buf) { - super.writeToByteBuffer(buf); - buf.putShort(getScaledLifetimePlc(lifetime, prefixLengthToPlc(prefix.getPrefixLength()))); - buf.put(prefix.getRawAddress(), 0, 12); - } - - /** Outputs the wire format of the option to a new big-endian ByteBuffer. */ - public ByteBuffer toByteBuffer() { - ByteBuffer buf = ByteBuffer.allocate(STRUCT_SIZE); - writeToByteBuffer(buf); - buf.flip(); - return buf; - } - - @Override - @NonNull - public String toString() { - return String.format("NdOptPref64(%s, %d)", prefix, lifetime); - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructNdOptRdnss.java b/common/device/com/android/net/module/util/netlink/StructNdOptRdnss.java deleted file mode 100644 index 6dee0c49..00000000 --- a/common/device/com/android/net/module/util/netlink/StructNdOptRdnss.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.net.module.util.netlink; - -import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_LEN; - -import android.util.Log; - -import androidx.annotation.NonNull; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.structs.RdnssOption; - -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.util.Objects; -import java.util.StringJoiner; - -/** - * The Recursive DNS Server Option. RFC 8106. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Length | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Lifetime | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * : Addresses of IPv6 Recursive DNS Servers : - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class StructNdOptRdnss extends NdOption { - private static final String TAG = StructNdOptRdnss.class.getSimpleName(); - public static final int TYPE = 25; - // Length in 8-byte units, only if one IPv6 address included. - public static final byte MIN_OPTION_LEN = 3; - - public final RdnssOption header; - @NonNull - public final Inet6Address[] servers; - - public StructNdOptRdnss(@NonNull final Inet6Address[] servers, long lifetime) { - super((byte) TYPE, servers.length * 2 + 1); - - Objects.requireNonNull(servers, "Recursive DNS Servers address array must not be null"); - if (servers.length == 0) { - throw new IllegalArgumentException("DNS server address array must not be empty"); - } - - this.header = new RdnssOption((byte) TYPE, (byte) (servers.length * 2 + 1), - (short) 0 /* reserved */, lifetime); - this.servers = servers.clone(); - } - - /** - * Parses an RDNSS option from a {@link ByteBuffer}. - * - * @param buf The buffer from which to parse the option. The buffer's byte order must be - * {@link java.nio.ByteOrder#BIG_ENDIAN}. - * @return the parsed option, or {@code null} if the option could not be parsed successfully. - */ - public static StructNdOptRdnss parse(@NonNull ByteBuffer buf) { - if (buf == null || buf.remaining() < MIN_OPTION_LEN * 8) return null; - try { - final RdnssOption header = Struct.parse(RdnssOption.class, buf); - if (header.type != TYPE) { - throw new IllegalArgumentException("Invalid type " + header.type); - } - if (header.length < MIN_OPTION_LEN || (header.length % 2 == 0)) { - throw new IllegalArgumentException("Invalid length " + header.length); - } - - final int numOfDnses = (header.length - 1) / 2; - final Inet6Address[] servers = new Inet6Address[numOfDnses]; - for (int i = 0; i < numOfDnses; i++) { - byte[] rawAddress = new byte[IPV6_ADDR_LEN]; - buf.get(rawAddress); - servers[i] = (Inet6Address) InetAddress.getByAddress(rawAddress); - } - return new StructNdOptRdnss(servers, header.lifetime); - } catch (IllegalArgumentException | BufferUnderflowException | UnknownHostException e) { - // Not great, but better than throwing an exception that might crash the caller. - // Convention in this package is that null indicates that the option was truncated - // or malformed, so callers must already handle it. - Log.d(TAG, "Invalid RDNSS option: " + e); - return null; - } - } - - protected void writeToByteBuffer(ByteBuffer buf) { - header.writeToByteBuffer(buf); - for (int i = 0; i < servers.length; i++) { - buf.put(servers[i].getAddress()); - } - } - - /** Outputs the wire format of the option to a new big-endian ByteBuffer. */ - public ByteBuffer toByteBuffer() { - final ByteBuffer buf = ByteBuffer.allocate(Struct.getSize(RdnssOption.class) - + servers.length * IPV6_ADDR_LEN); - writeToByteBuffer(buf); - buf.flip(); - return buf; - } - - @Override - @NonNull - public String toString() { - final StringJoiner sj = new StringJoiner(",", "[", "]"); - for (int i = 0; i < servers.length; i++) { - sj.add(servers[i].getHostAddress()); - } - return String.format("NdOptRdnss(%s,servers:%s)", header.toString(), sj.toString()); - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructNdaCacheInfo.java b/common/device/com/android/net/module/util/netlink/StructNdaCacheInfo.java deleted file mode 100644 index 1f9bb7ec..00000000 --- a/common/device/com/android/net/module/util/netlink/StructNdaCacheInfo.java +++ /dev/null @@ -1,123 +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 com.android.net.module.util.netlink; - -import static com.android.net.module.util.netlink.NetlinkUtils.ticksToMilliSeconds; - -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; - } - - /** - * Parse a nd cacheinfo netlink attribute from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the nd cacheinfo attribute. - * @return the parsed nd cacheinfo attribute, or {@code null} if the nd cacheinfo attribute - * could not be parsed successfully (for example, if it was truncated). - */ - 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; - } - - /** - * 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() {} - - /** - * The last time ARP/ND took place for this neighbor. - */ - public long lastUsed() { - return ticksToMilliSeconds(ndm_used); - } - - /** - * The last time ARP/ND succeeded for this neighbor or higher layer confirmation (TCP or - * MSG_CONFIRM) was received. - */ - public long lastConfirmed() { - return ticksToMilliSeconds(ndm_confirmed); - } - - /** - * The time when the current NUD state was entered. - */ - 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 + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructNfGenMsg.java b/common/device/com/android/net/module/util/netlink/StructNfGenMsg.java deleted file mode 100644 index 2de5490b..00000000 --- a/common/device/com/android/net/module/util/netlink/StructNfGenMsg.java +++ /dev/null @@ -1,105 +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 com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Objects; - -/** - * 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; - - public final byte nfgen_family; - public final byte version; - public final short res_id; // N.B.: this is big endian in the kernel - - /** - * Parse a netfilter netlink header from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the netfilter netlink header. - * @return the parsed netfilter netlink header, or {@code null} if the netfilter netlink header - * could not be parsed successfully (for example, if it was truncated). - */ - @Nullable - public static StructNfGenMsg parse(@NonNull ByteBuffer byteBuffer) { - Objects.requireNonNull(byteBuffer); - - if (!hasAvailableSpace(byteBuffer)) return null; - - final byte nfgen_family = byteBuffer.get(); - final byte version = byteBuffer.get(); - - final ByteOrder originalOrder = byteBuffer.order(); - byteBuffer.order(ByteOrder.BIG_ENDIAN); - final short res_id = byteBuffer.getShort(); - byteBuffer.order(originalOrder); - - return new StructNfGenMsg(nfgen_family, version, res_id); - } - - public StructNfGenMsg(byte family, byte ver, short id) { - nfgen_family = family; - version = ver; - res_id = id; - } - - public StructNfGenMsg(byte family) { - nfgen_family = family; - version = (byte) NFNETLINK_V0; - res_id = (short) 0; - } - - /** - * Write a netfilter netlink header to a {@link ByteBuffer}. - */ - public void pack(ByteBuffer byteBuffer) { - byteBuffer.put(nfgen_family); - byteBuffer.put(version); - - final ByteOrder originalOrder = byteBuffer.order(); - byteBuffer.order(ByteOrder.BIG_ENDIAN); - byteBuffer.putShort(res_id); - byteBuffer.order(originalOrder); - } - - private static boolean hasAvailableSpace(@NonNull ByteBuffer byteBuffer) { - return byteBuffer.remaining() >= STRUCT_SIZE; - } - - @Override - public String toString() { - final String familyStr = NetlinkConstants.stringForAddressFamily(nfgen_family); - - return "NfGenMsg{ " - + "nfgen_family{" + familyStr + "}, " - + "version{" + Byte.toUnsignedInt(version) + "}, " - + "res_id{" + Short.toUnsignedInt(res_id) + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructNlAttr.java b/common/device/com/android/net/module/util/netlink/StructNlAttr.java deleted file mode 100644 index a9b64950..00000000 --- a/common/device/com/android/net/module/util/netlink/StructNlAttr.java +++ /dev/null @@ -1,394 +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 com.android.net.module.util.netlink; - -import android.net.MacAddress; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.io.UnsupportedEncodingException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Arrays; - -/** - * 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); - - /** - * Set carries nested attributes bit. - */ - public static short makeNestedType(short type) { - return (short) (type | NLA_F_NESTED); - } - - /** - * Peek and parse the netlink attribute from {@link ByteBuffer}. - * - * 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(); - - final StructNlAttr struct = new StructNlAttr(); - 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; - } - - /** - * Parse a netlink attribute from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the netlink attriute. - * @return the parsed netlink attribute, or {@code null} if the netlink attribute - * could not be parsed successfully (for example, if it was truncated). - */ - 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; - } - - /** - * Find next netlink attribute with a given type from {@link ByteBuffer}. - * - * @param attrType The given netlink attribute type is requested for. - * @param byteBuffer The buffer from which to find the netlink attribute. - * @return the found netlink attribute, or {@code null} if the netlink attribute could not be - * found or parsed successfully (for example, if it was truncated). - */ - @Nullable - public static StructNlAttr findNextAttrOfType(short attrType, - @Nullable 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 short nla_len = (short) NLA_HEADERLEN; - public short nla_type; - public byte[] nla_value; - - public StructNlAttr() {} - - 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) { - nla_type = type; - setValue(new byte[Short.BYTES]); - final ByteBuffer buf = getValueAsByteBuffer(); - final ByteOrder originalOrder = buf.order(); - try { - buf.order(order); - buf.putShort(value); - } finally { - buf.order(originalOrder); - } - } - - public StructNlAttr(short type, int value) { - this(type, value, ByteOrder.nativeOrder()); - } - - public StructNlAttr(short type, int value, ByteOrder order) { - nla_type = type; - setValue(new byte[Integer.BYTES]); - final ByteBuffer buf = getValueAsByteBuffer(); - final ByteOrder originalOrder = buf.order(); - try { - buf.order(order); - buf.putInt(value); - } finally { - buf.order(originalOrder); - } - } - - public StructNlAttr(short type, @NonNull final byte[] value) { - nla_type = type; - setValue(value); - } - - public StructNlAttr(short type, @NonNull final InetAddress ip) { - nla_type = type; - setValue(ip.getAddress()); - } - - public StructNlAttr(short type, @NonNull final MacAddress mac) { - nla_type = type; - setValue(mac.toByteArray()); - } - - public StructNlAttr(short type, @NonNull final String string) { - nla_type = type; - byte[] value = null; - try { - final byte[] stringBytes = string.getBytes("UTF-8"); - // Append '\0' at the end of interface name string bytes. - value = Arrays.copyOf(stringBytes, stringBytes.length + 1); - } catch (UnsupportedEncodingException ignored) { - // Do nothing. - } finally { - setValue(value); - } - } - - 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); - } - } - - /** - * Get aligned attribute length. - */ - public int getAlignedLength() { - return NetlinkConstants.alignedLengthOf(nla_len); - } - - /** - * Get attribute value as BE16. - */ - public short getValueAsBe16(short defaultValue) { - final ByteBuffer byteBuffer = getValueAsByteBuffer(); - if (byteBuffer == null || byteBuffer.remaining() != Short.BYTES) { - return defaultValue; - } - final ByteOrder originalOrder = byteBuffer.order(); - try { - byteBuffer.order(ByteOrder.BIG_ENDIAN); - return byteBuffer.getShort(); - } finally { - byteBuffer.order(originalOrder); - } - } - - /** - * Get attribute value as BE32. - */ - public int getValueAsBe32(int defaultValue) { - final ByteBuffer byteBuffer = getValueAsByteBuffer(); - if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) { - return defaultValue; - } - final ByteOrder originalOrder = byteBuffer.order(); - try { - byteBuffer.order(ByteOrder.BIG_ENDIAN); - return byteBuffer.getInt(); - } finally { - byteBuffer.order(originalOrder); - } - } - - /** - * Get attribute value as ByteBuffer. - */ - public ByteBuffer getValueAsByteBuffer() { - if (nla_value == null) return null; - final ByteBuffer byteBuffer = ByteBuffer.wrap(nla_value); - // By convention, all buffers in this library are in native byte order because netlink is in - // native byte order. It's the order that is used by NetlinkSocket.recvMessage and the only - // order accepted by NetlinkMessage.parse. - byteBuffer.order(ByteOrder.nativeOrder()); - return byteBuffer; - } - - /** - * Get attribute value as byte. - */ - public byte getValueAsByte(byte defaultValue) { - final ByteBuffer byteBuffer = getValueAsByteBuffer(); - if (byteBuffer == null || byteBuffer.remaining() != Byte.BYTES) { - return defaultValue; - } - return getValueAsByteBuffer().get(); - } - - /** - * Get attribute value as Integer, or null if malformed (e.g., length is not 4 bytes). - */ - public Integer getValueAsInteger() { - final ByteBuffer byteBuffer = getValueAsByteBuffer(); - if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) { - return null; - } - return byteBuffer.getInt(); - } - - /** - * Get attribute value as Int, default value if malformed. - */ - public int getValueAsInt(int defaultValue) { - final Integer value = getValueAsInteger(); - return (value != null) ? value : defaultValue; - } - - /** - * Get attribute value as InetAddress. - * - * @return the InetAddress instance representation of attribute value or null if IP address - * is of illegal length. - */ - @Nullable - public InetAddress getValueAsInetAddress() { - if (nla_value == null) return null; - - try { - return InetAddress.getByAddress(nla_value); - } catch (UnknownHostException ignored) { - return null; - } - } - - /** - * Get attribute value as MacAddress. - * - * @return the MacAddress instance representation of attribute value or null if the given byte - * array is not a valid representation(e.g, not all link layers have 6-byte link-layer - * addresses) - */ - @Nullable - public MacAddress getValueAsMacAddress() { - if (nla_value == null) return null; - - try { - return MacAddress.fromBytes(nla_value); - } catch (IllegalArgumentException ignored) { - return null; - } - } - - /** - * Get attribute value as a unicode string. - * - * @return a unicode string or null if UTF-8 charset is not supported. - */ - @Nullable - public String getValueAsString() { - if (nla_value == null) return null; - // Check the attribute value length after removing string termination flag '\0'. - // This assumes that all netlink strings are null-terminated. - if (nla_value.length < (nla_len - NLA_HEADERLEN - 1)) return null; - - try { - final byte[] array = Arrays.copyOf(nla_value, nla_len - NLA_HEADERLEN - 1); - return new String(array, "UTF-8"); - } catch (UnsupportedEncodingException | NegativeArraySizeException ignored) { - return null; - } - } - - /** - * Write the netlink attribute to {@link ByteBuffer}. - */ - 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) + "}, " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructNlMsgErr.java b/common/device/com/android/net/module/util/netlink/StructNlMsgErr.java deleted file mode 100644 index b6620f3b..00000000 --- a/common/device/com/android/net/module/util/netlink/StructNlMsgErr.java +++ /dev/null @@ -1,77 +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 com.android.net.module.util.netlink; - -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; - - private static boolean hasAvailableSpace(ByteBuffer byteBuffer) { - return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE; - } - - /** - * Parse a netlink error message payload from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the netlink error message payload. - * @return the parsed netlink error message payload, or {@code null} if the netlink error - * message payload could not be parsed successfully (for example, if it was truncated). - */ - 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; - - /** - * Write the netlink error message payload to {@link ByteBuffer}. - */ - 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()) + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructNlMsgHdr.java b/common/device/com/android/net/module/util/netlink/StructNlMsgHdr.java deleted file mode 100644 index 5052cb8a..00000000 --- a/common/device/com/android/net/module/util/netlink/StructNlMsgHdr.java +++ /dev/null @@ -1,174 +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 com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -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; - - // TODO: Probably need to distinguish the flags which have the same value. For example, - // NLM_F_MATCH (0x200) and NLM_F_EXCL (0x200). - private 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(); - } - - private static boolean hasAvailableSpace(ByteBuffer byteBuffer) { - return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE; - } - - /** - * Parse netlink message header from buffer. - */ - @Nullable - public static StructNlMsgHdr parse(@NonNull 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; - } - - /** - * Write netlink message header to ByteBuffer. - */ - 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() { - return toString(null /* unknown netlink family */); - } - - /** - * Transform a netlink header into a string. The netlink family is required for transforming - * a netlink type integer into a string. - * @param nlFamily netlink family. Using Integer will not incur autoboxing penalties because - * family values are small, and all Integer objects between -128 and 127 are - * statically cached. See Integer.IntegerCache. - * @return A list of header elements. - */ - @NonNull - public String toString(@Nullable Integer nlFamily) { - final String typeStr = "" + nlmsg_type - + "(" + (nlFamily == null - ? "" : NetlinkConstants.stringForNlMsgType(nlmsg_type, nlFamily)) - + ")"; - 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 + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructRtMsg.java b/common/device/com/android/net/module/util/netlink/StructRtMsg.java deleted file mode 100644 index 3cd72922..00000000 --- a/common/device/com/android/net/module/util/netlink/StructRtMsg.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; - -/** - * struct rtmsg - * - * see also: - * - * include/uapi/linux/rtnetlink.h - * - * @hide - */ -public class StructRtMsg extends Struct { - // Already aligned. - public static final int STRUCT_SIZE = 12; - - @Field(order = 0, type = Type.U8) - public final short family; // Address family of route. - @Field(order = 1, type = Type.U8) - public final short dstLen; // Length of destination. - @Field(order = 2, type = Type.U8) - public final short srcLen; // Length of source. - @Field(order = 3, type = Type.U8) - public final short tos; // TOS filter. - @Field(order = 4, type = Type.U8) - public final short table; // Routing table ID. - @Field(order = 5, type = Type.U8) - public final short protocol; // Routing protocol. - @Field(order = 6, type = Type.U8) - public final short scope; // distance to the destination. - @Field(order = 7, type = Type.U8) - public final short type; // route type - @Field(order = 8, type = Type.U32) - public final long flags; - - StructRtMsg(short family, short dstLen, short srcLen, short tos, short table, short protocol, - short scope, short type, long flags) { - this.family = family; - this.dstLen = dstLen; - this.srcLen = srcLen; - this.tos = tos; - this.table = table; - this.protocol = protocol; - this.scope = scope; - this.type = type; - this.flags = flags; - } - - /** - * Parse a rtmsg struct from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the rtmsg struct. - * @return the parsed rtmsg struct, or {@code null} if the rtmsg struct could not be - * parsed successfully (for example, if it was truncated). - */ - @Nullable - public static StructRtMsg parse(@NonNull final ByteBuffer byteBuffer) { - if (byteBuffer.remaining() < STRUCT_SIZE) return null; - - // The ByteOrder must already have been set to native order. - return Struct.parse(StructRtMsg.class, byteBuffer); - } - - /** - * Write the rtmsg struct to {@link ByteBuffer}. - */ - public void pack(@NonNull final ByteBuffer byteBuffer) { - // The ByteOrder must already have been set to native order. - this.writeToByteBuffer(byteBuffer); - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructRtaCacheInfo.java b/common/device/com/android/net/module/util/netlink/StructRtaCacheInfo.java deleted file mode 100644 index fef1f9e8..00000000 --- a/common/device/com/android/net/module/util/netlink/StructRtaCacheInfo.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; - -/** - * struct rta_cacheinfo - * - * see also: - * - * include/uapi/linux/rtnetlink.h - * - * @hide - */ -public class StructRtaCacheInfo extends Struct { - // Already aligned. - public static final int STRUCT_SIZE = 32; - - @Field(order = 0, type = Type.U32) - public final long clntref; - @Field(order = 1, type = Type.U32) - public final long lastuse; - @Field(order = 2, type = Type.S32) - public final int expires; - @Field(order = 3, type = Type.U32) - public final long error; - @Field(order = 4, type = Type.U32) - public final long used; - @Field(order = 5, type = Type.U32) - public final long id; - @Field(order = 6, type = Type.U32) - public final long ts; - @Field(order = 7, type = Type.U32) - public final long tsage; - - StructRtaCacheInfo(long clntref, long lastuse, int expires, long error, long used, long id, - long ts, long tsage) { - this.clntref = clntref; - this.lastuse = lastuse; - this.expires = expires; - this.error = error; - this.used = used; - this.id = id; - this.ts = ts; - this.tsage = tsage; - } - - /** - * Parse an rta_cacheinfo struct from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the rta_cacheinfo. - * @return the parsed rta_cacheinfo struct, or {@code null} if the rta_cacheinfo struct - * could not be parsed successfully (for example, if it was truncated). - */ - @Nullable - public static StructRtaCacheInfo parse(@NonNull final ByteBuffer byteBuffer) { - if (byteBuffer.remaining() < STRUCT_SIZE) return null; - - // The ByteOrder must already have been set to native order. - return Struct.parse(StructRtaCacheInfo.class, byteBuffer); - } - - /** - * Write a rta_cacheinfo struct to {@link ByteBuffer}. - */ - public void pack(@NonNull final ByteBuffer byteBuffer) { - // The ByteOrder must already have been set to native order. - this.writeToByteBuffer(byteBuffer); - } -} |