Add a method helper to create RTM_DELADDR message in user space.
Bug: 260934173
Bug: 263222068
Test: atest NetworkStaticLibTests
Change-Id: Ibddaed91b12d3f27778d0bd2171bc5be38ff8bda
diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
index 0f7bd80..73c88c7 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
@@ -196,6 +196,27 @@
}
/**
+ * 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.
diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java
index 2829b92..cbe0ab0 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java
@@ -161,7 +161,7 @@
}
/**
- * A convenience method to create an RTM_NEWADDR message.
+ * 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) {
@@ -192,6 +192,51 @@
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
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java
index 99d96b5..01126d2 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java
@@ -179,6 +179,34 @@
}
@Test
+ public void testCreateRtmDelAddressMessage() {
+ // Hexadecimal representation of our created packet.
+ final String expectedDelAddressHex =
+ // struct nlmsghdr
+ "2C000000" + // length = 44
+ "1500" + // type = 21 (RTM_DELADDR)
+ "0500" + // flags = NLM_F_ACK | NLM_F_REQUEST
+ "01000000" + // seqno = 1
+ "00000000" + // pid = 0 (send to kernel)
+ // struct IfaddrMsg
+ "0A" + // family = inet6
+ "40" + // prefix len = 64
+ "00" + // flags = 0
+ "00" + // scope = RT_SCOPE_UNIVERSE
+ "3B000000" + // ifindex = 59
+ // struct nlattr: IFA_ADDRESS
+ "1400" + // len
+ "0100" + // type
+ "20010DB8000100000000000000000100"; // IP address = 2001:db8:1::100
+ final byte[] expectedDelAddress =
+ HexEncoding.decode(expectedDelAddressHex.toCharArray(), false);
+
+ final byte[] bytes = RtNetlinkAddressMessage.newRtmDelAddressMessage(1 /* seqno */,
+ TEST_GLOBAL_ADDRESS, (short) 64 /* prefix len */, 59 /* ifindex */);
+ assertArrayEquals(expectedDelAddress, bytes);
+ }
+
+ @Test
public void testCreateRtmNewAddressMessage_nullIpAddress() {
assertThrows(NullPointerException.class,
() -> RtNetlinkAddressMessage.newRtmNewAddressMessage(1 /* seqno */,
@@ -189,6 +217,13 @@
}
@Test
+ public void testCreateRtmDelAddressMessage_nullIpAddress() {
+ assertThrows(NullPointerException.class,
+ () -> RtNetlinkAddressMessage.newRtmDelAddressMessage(1 /* seqno */,
+ null /* IP address */, (short) 0 /* prefix len */, 59 /* ifindex */));
+ }
+
+ @Test
public void testCreateRtmNewAddressMessage_u32Flags() {
// Hexadecimal representation of our created packet.
final String expectedNewAddressHex =