Merge "Support adding an IPv4 address via RTM_NEWADDR netlink message." into main
This commit is contained in:
commit
522197af33
3 changed files with 96 additions and 12 deletions
|
|
@ -29,6 +29,7 @@ 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 static com.android.net.module.util.netlink.NetlinkConstants.hexify;
|
||||
import static com.android.net.module.util.netlink.NetlinkConstants.NLMSG_DONE;
|
||||
import static com.android.net.module.util.netlink.NetlinkConstants.RTNL_FAMILY_IP6MR;
|
||||
|
|
@ -49,6 +50,7 @@ import java.io.FileDescriptor;
|
|||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.SocketException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
|
@ -56,7 +58,6 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Utilities for netlink related class that may not be able to fit into a specific class.
|
||||
|
|
@ -177,19 +178,19 @@ public class NetlinkUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Send an RTM_NEWADDR message to kernel to add or update an IPv6 address.
|
||||
* Send an RTM_NEWADDR message to kernel to add or update an IP 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.
|
||||
* @param ip IP address to be added.
|
||||
* @param prefixlen IP address prefix length.
|
||||
* @param flags IP address flags.
|
||||
* @param scope IP address scope.
|
||||
* @param preferred The preferred lifetime of IP address.
|
||||
* @param valid The valid lifetime of IP address.
|
||||
*/
|
||||
public static boolean sendRtmNewAddressRequest(int ifIndex, @NonNull final Inet6Address ip,
|
||||
public static boolean sendRtmNewAddressRequest(int ifIndex, @NonNull final InetAddress ip,
|
||||
short prefixlen, int flags, byte scope, long preferred, long valid) {
|
||||
Objects.requireNonNull(ip, "IPv6 address to be added should not be null.");
|
||||
Objects.requireNonNull(ip, "IP address to be added should not be null.");
|
||||
final byte[] msg = RtNetlinkAddressMessage.newRtmNewAddressMessage(1 /* seqNo*/, ip,
|
||||
prefixlen, flags, scope, ifIndex, preferred, valid);
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package com.android.net.module.util.netlink;
|
||||
|
||||
import static com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress;
|
||||
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;
|
||||
|
|
@ -28,6 +29,7 @@ import androidx.annotation.VisibleForTesting;
|
|||
|
||||
import com.android.net.module.util.HexDump;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
|
|
@ -48,6 +50,8 @@ import java.util.Objects;
|
|||
*/
|
||||
public class RtNetlinkAddressMessage extends NetlinkMessage {
|
||||
public static final short IFA_ADDRESS = 1;
|
||||
public static final short IFA_LOCAL = 2;
|
||||
public static final short IFA_BROADCAST = 4;
|
||||
public static final short IFA_CACHEINFO = 6;
|
||||
public static final short IFA_FLAGS = 8;
|
||||
|
||||
|
|
@ -71,6 +75,7 @@ public class RtNetlinkAddressMessage extends NetlinkMessage {
|
|||
mIfacacheInfo = structIfacacheInfo;
|
||||
mFlags = flags;
|
||||
}
|
||||
|
||||
private RtNetlinkAddressMessage(@NonNull StructNlMsgHdr header) {
|
||||
this(header, null, null, null, 0);
|
||||
}
|
||||
|
|
@ -158,6 +163,24 @@ public class RtNetlinkAddressMessage extends NetlinkMessage {
|
|||
// still be packed to ByteBuffer even if the flag is 0.
|
||||
final StructNlAttr flags = new StructNlAttr(IFA_FLAGS, mFlags);
|
||||
flags.pack(byteBuffer);
|
||||
|
||||
// Add the required IFA_LOCAL and IFA_BROADCAST attributes for IPv4 addresses. The IFA_LOCAL
|
||||
// attribute represents the local address, which is equivalent to IFA_ADDRESS on a normally
|
||||
// configured broadcast interface, however, for PPP interfaces, IFA_ADDRESS indicates the
|
||||
// destination address and the local address is provided in the IFA_LOCAL attribute. If the
|
||||
// IFA_LOCAL attribute is not present in the RTM_NEWADDR message, the kernel replies with an
|
||||
// error netlink message with invalid parameters. IFA_BROADCAST is also required, otherwise
|
||||
// the broadcast on the interface is 0.0.0.0. See include/uapi/linux/if_addr.h for details.
|
||||
// For IPv6 addresses, the IFA_ADDRESS attribute applies and introduces no ambiguity.
|
||||
if (mIpAddress instanceof Inet4Address) {
|
||||
final StructNlAttr localAddress = new StructNlAttr(IFA_LOCAL, mIpAddress);
|
||||
localAddress.pack(byteBuffer);
|
||||
|
||||
final Inet4Address broadcast =
|
||||
getBroadcastAddress((Inet4Address) mIpAddress, mIfaddrmsg.prefixLen);
|
||||
final StructNlAttr broadcastAddress = new StructNlAttr(IFA_BROADCAST, broadcast);
|
||||
broadcastAddress.pack(byteBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -184,7 +207,7 @@ public class RtNetlinkAddressMessage extends NetlinkMessage {
|
|||
0 /* tstamp */);
|
||||
msg.mFlags = flags;
|
||||
|
||||
final byte[] bytes = new byte[msg.getRequiredSpace()];
|
||||
final byte[] bytes = new byte[msg.getRequiredSpace(family)];
|
||||
nlmsghdr.nlmsg_len = bytes.length;
|
||||
final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
|
||||
byteBuffer.order(ByteOrder.nativeOrder());
|
||||
|
|
@ -237,7 +260,7 @@ public class RtNetlinkAddressMessage extends NetlinkMessage {
|
|||
// 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() {
|
||||
private int getRequiredSpace(int family) {
|
||||
int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructIfaddrMsg.STRUCT_SIZE;
|
||||
// IFA_ADDRESS attr
|
||||
spaceRequired += NetlinkConstants.alignedLengthOf(
|
||||
|
|
@ -247,6 +270,14 @@ public class RtNetlinkAddressMessage extends NetlinkMessage {
|
|||
StructNlAttr.NLA_HEADERLEN + StructIfacacheInfo.STRUCT_SIZE);
|
||||
// IFA_FLAGS "u32" attr
|
||||
spaceRequired += StructNlAttr.NLA_HEADERLEN + 4;
|
||||
if (family == OsConstants.AF_INET) {
|
||||
// IFA_LOCAL attr
|
||||
spaceRequired += NetlinkConstants.alignedLengthOf(
|
||||
StructNlAttr.NLA_HEADERLEN + mIpAddress.getAddress().length);
|
||||
// IFA_BROADCAST attr
|
||||
spaceRequired += NetlinkConstants.alignedLengthOf(
|
||||
StructNlAttr.NLA_HEADERLEN + mIpAddress.getAddress().length);
|
||||
}
|
||||
return spaceRequired;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import libcore.util.HexEncoding;
|
|||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
|
@ -178,6 +179,57 @@ public class RtNetlinkAddressMessageTest {
|
|||
assertArrayEquals(expectedNewAddress, bytes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateRtmNewAddressMessage_IPv4Address() {
|
||||
// Hexadecimal representation of our created packet.
|
||||
final String expectedNewAddressHex =
|
||||
// struct nlmsghdr
|
||||
"4c000000" // length = 76
|
||||
+ "1400" // type = 20 (RTM_NEWADDR)
|
||||
+ "0501" // flags = NLM_F_ACK | NLM_F_REQUEST | NLM_F_REPLACE
|
||||
+ "01000000" // seqno = 1
|
||||
+ "00000000" // pid = 0 (send to kernel)
|
||||
// struct IfaddrMsg
|
||||
+ "02" // family = inet
|
||||
+ "18" // prefix len = 24
|
||||
+ "00" // flags = 0
|
||||
+ "00" // scope = RT_SCOPE_UNIVERSE
|
||||
+ "14000000" // ifindex = 20
|
||||
// struct nlattr: IFA_ADDRESS
|
||||
+ "0800" // len
|
||||
+ "0100" // type
|
||||
+ "C0A80491" // IPv4 address = 192.168.4.145
|
||||
// struct nlattr: IFA_CACHEINFO
|
||||
+ "1400" // len
|
||||
+ "0600" // type
|
||||
+ "C0A80000" // preferred = 43200s
|
||||
+ "C0A80000" // valid = 43200s
|
||||
+ "00000000" // cstamp
|
||||
+ "00000000" // tstamp
|
||||
// struct nlattr: IFA_FLAGS
|
||||
+ "0800" // len
|
||||
+ "0800" // type
|
||||
+ "00000000" // flags = 0
|
||||
// struct nlattr: IFA_LOCAL
|
||||
+ "0800" // len
|
||||
+ "0200" // type
|
||||
+ "C0A80491" // local address = 192.168.4.145
|
||||
// struct nlattr: IFA_BROADCAST
|
||||
+ "0800" // len
|
||||
+ "0400" // type
|
||||
+ "C0A804FF"; // broadcast address = 192.168.4.255
|
||||
final byte[] expectedNewAddress =
|
||||
HexEncoding.decode(expectedNewAddressHex.toCharArray(), false);
|
||||
|
||||
final Inet4Address ipAddress =
|
||||
(Inet4Address) InetAddresses.parseNumericAddress("192.168.4.145");
|
||||
final byte[] bytes = RtNetlinkAddressMessage.newRtmNewAddressMessage(1 /* seqno */,
|
||||
ipAddress, (short) 24 /* prefix len */, 0 /* flags */,
|
||||
(byte) RT_SCOPE_UNIVERSE /* scope */, 20 /* ifindex */,
|
||||
(long) 0xA8C0 /* preferred */, (long) 0xA8C0 /* valid */);
|
||||
assertArrayEquals(expectedNewAddress, bytes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateRtmDelAddressMessage() {
|
||||
// Hexadecimal representation of our created packet.
|
||||
|
|
|
|||
Loading…
Reference in a new issue