summaryrefslogtreecommitdiff
path: root/common/device/com/android/net/module/util
diff options
context:
space:
mode:
Diffstat (limited to 'common/device/com/android/net/module/util')
-rw-r--r--common/device/com/android/net/module/util/netlink/NetlinkConstants.java14
-rw-r--r--common/device/com/android/net/module/util/netlink/NetlinkMessage.java3
-rw-r--r--common/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java193
-rw-r--r--common/device/com/android/net/module/util/netlink/StructRtMsg.java95
4 files changed, 305 insertions, 0 deletions
diff --git a/common/device/com/android/net/module/util/netlink/NetlinkConstants.java b/common/device/com/android/net/module/util/netlink/NetlinkConstants.java
index 07b52d8c..83a82b74 100644
--- a/common/device/com/android/net/module/util/netlink/NetlinkConstants.java
+++ b/common/device/com/android/net/module/util/netlink/NetlinkConstants.java
@@ -146,12 +146,26 @@ public class NetlinkConstants {
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_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.
*/
diff --git a/common/device/com/android/net/module/util/netlink/NetlinkMessage.java b/common/device/com/android/net/module/util/netlink/NetlinkMessage.java
index 708736e5..a216752b 100644
--- a/common/device/com/android/net/module/util/netlink/NetlinkMessage.java
+++ b/common/device/com/android/net/module/util/netlink/NetlinkMessage.java
@@ -126,6 +126,9 @@ public class NetlinkMessage {
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:
diff --git a/common/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java b/common/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java
new file mode 100644
index 00000000..c5efcb26
--- /dev/null
+++ b/common/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java
@@ -0,0 +1,193 @@
+/*
+ * 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.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;
+
+ private int mIfindex;
+ @NonNull
+ private StructRtMsg mRtmsg;
+ @NonNull
+ private IpPrefix mDestination;
+ @Nullable
+ private InetAddress mGateway;
+
+ private RtNetlinkRouteMessage(StructNlMsgHdr header) {
+ super(header);
+ mRtmsg = null;
+ mDestination = null;
+ mGateway = null;
+ mIfindex = 0;
+ }
+
+ public int getInterfaceIndex() {
+ return mIfindex;
+ }
+
+ @NonNull
+ public StructRtMsg getRtMsgHeader() {
+ return mRtmsg;
+ }
+
+ @NonNull
+ public IpPrefix getDestination() {
+ return mDestination;
+ }
+
+ @Nullable
+ public InetAddress getGateway() {
+ return mGateway;
+ }
+
+ /**
+ * 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.
+ */
+ @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 */);
+ }
+
+ 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);
+ }
+ }
+
+ @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 + "} "
+ + "}";
+ }
+}
diff --git a/common/device/com/android/net/module/util/netlink/StructRtMsg.java b/common/device/com/android/net/module/util/netlink/StructRtMsg.java
new file mode 100644
index 00000000..3cd72922
--- /dev/null
+++ b/common/device/com/android/net/module/util/netlink/StructRtMsg.java
@@ -0,0 +1,95 @@
+/*
+ * 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);
+ }
+}