diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-06-08 17:28:31 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-06-08 17:28:31 +0000 |
commit | 82ea1ce979f30172399702a717210615e2f5a147 (patch) | |
tree | 799cd95e915f619f14c686b98aa964babdabb87e | |
parent | 46f19e4a25ffc7cc8fb688e54692bbb47ebceb52 (diff) | |
parent | acea63e2786d776ed23915f5d3af31a7d14eb622 (diff) | |
download | net-82ea1ce979f30172399702a717210615e2f5a147.tar.gz |
Snap for 10276566 from acea63e2786d776ed23915f5d3af31a7d14eb622 to tm-platform-releaseandroid-platform-13.0.0_r9android-platform-13.0.0_r8android-platform-13.0.0_r21android-platform-13.0.0_r20android-platform-13.0.0_r19android-platform-13.0.0_r18android-platform-13.0.0_r17android-platform-13.0.0_r16android-platform-13.0.0_r15android-platform-13.0.0_r14android-platform-13.0.0_r13android-platform-13.0.0_r12android-platform-13.0.0_r11android-platform-13.0.0_r10android13-platform-release
Change-Id: I1aa46039907e7b975361f9132aad25b2dcfbfdcb
-rw-r--r-- | common/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java | 138 |
1 files changed, 107 insertions, 31 deletions
diff --git a/common/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java b/common/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java index 4ad93d85..51df9351 100644 --- a/common/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java +++ b/common/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java @@ -18,19 +18,21 @@ package com.android.testutils; import static android.system.OsConstants.IPPROTO_ICMPV6; -import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN; -import static com.android.net.module.util.NetworkStackConstants.ETHER_SRC_ADDR_OFFSET; import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION; import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_NODES_MULTICAST; -import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST; +import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE; +import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER; +import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED; import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_AUTONOMOUS; import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_ON_LINK; import android.net.InetAddresses; import android.net.IpPrefix; -import android.net.LinkAddress; import android.net.MacAddress; +import android.util.ArrayMap; import android.util.Pair; import com.android.net.module.util.Ipv6Utils; @@ -38,45 +40,64 @@ import com.android.net.module.util.Struct; import com.android.net.module.util.structs.EthernetHeader; import com.android.net.module.util.structs.Icmpv6Header; import com.android.net.module.util.structs.Ipv6Header; +import com.android.net.module.util.structs.LlaOption; +import com.android.net.module.util.structs.NsHeader; import com.android.net.module.util.structs.PrefixInformationOption; import com.android.net.module.util.structs.RdnssOption; import java.io.IOException; import java.net.Inet6Address; import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Random; /** - * RA responder class useful for tests that require a provisioned interface. + * ND (RA & NA) responder class useful for tests that require a provisioned IPv6 interface. + * TODO: rename to NdResponder */ public class RouterAdvertisementResponder extends PacketResponder { private static final String TAG = "RouterAdvertisementResponder"; - private static final LinkAddress SLAAC_PREFIX = new LinkAddress("2001:db8::/64"); private static final Inet6Address DNS_SERVER = (Inet6Address) InetAddresses.parseNumericAddress("2001:4860:4860::64"); private final TapPacketReader mPacketReader; - private final List<Pair<MacAddress, Inet6Address>> mRouterList = new ArrayList<>(); + // Maps IPv6 address to MacAddress and isRouter boolean. + private final Map<Inet6Address, Pair<MacAddress, Boolean>> mNeighborMap = new ArrayMap<>(); + private final IpPrefix mPrefix; - public RouterAdvertisementResponder(TapPacketReader packetReader) { - super(packetReader, RouterAdvertisementResponder::isRouterSolicitation, TAG); + public RouterAdvertisementResponder(TapPacketReader packetReader, IpPrefix prefix) { + super(packetReader, RouterAdvertisementResponder::isRsOrNs, TAG); mPacketReader = packetReader; + mPrefix = Objects.requireNonNull(prefix); + } + + public RouterAdvertisementResponder(TapPacketReader packetReader) { + this(packetReader, makeRandomPrefix()); } - private static boolean isRouterSolicitation(byte[] packet) { + private static IpPrefix makeRandomPrefix() { + final byte[] prefixBytes = new IpPrefix("2001:db8::/64").getAddress().getAddress(); + final Random r = new Random(); + for (int i = 4; i < 8; i++) { + prefixBytes[i] = (byte) r.nextInt(); + } + return new IpPrefix(prefixBytes, 64); + } + + /** Returns true if the packet is a router solicitation or neighbor solicitation message. */ + private static boolean isRsOrNs(byte[] packet) { final ByteBuffer buffer = ByteBuffer.wrap(packet); final EthernetHeader ethHeader = Struct.parse(EthernetHeader.class, buffer); if (ethHeader.etherType != ETHER_TYPE_IPV6) { return false; } final Ipv6Header ipv6Header = Struct.parse(Ipv6Header.class, buffer); - if (ipv6Header.nextHeader != IPPROTO_ICMPV6 - || !ipv6Header.dstIp.equals(IPV6_ADDR_ALL_ROUTERS_MULTICAST)) { + if (ipv6Header.nextHeader != IPPROTO_ICMPV6) { return false; } final Icmpv6Header icmpv6Header = Struct.parse(Icmpv6Header.class, buffer); - return icmpv6Header.type == ICMPV6_ROUTER_SOLICITATION; + return icmpv6Header.type == ICMPV6_ROUTER_SOLICITATION + || icmpv6Header.type == ICMPV6_NEIGHBOR_SOLICITATION; } /** @@ -85,14 +106,29 @@ public class RouterAdvertisementResponder extends PacketResponder { * @param ip the link-local address of the router. */ public void addRouterEntry(MacAddress mac, Inet6Address ip) { - mRouterList.add(new Pair<>(mac, ip)); + mNeighborMap.put(ip, new Pair<>(mac, true)); + } + + /** + * Adds a new neighbor to be advertised. + * @param mac the mac address of the neighbor. + * @param ip the link-local address of the neighbor. + */ + public void addNeighborEntry(MacAddress mac, Inet6Address ip) { + mNeighborMap.put(ip, new Pair<>(mac, false)); + } + + /** + * @return the prefix that is announced in the Router Advertisements sent by this object. + */ + public IpPrefix getPrefix() { + return mPrefix; } private ByteBuffer buildPrefixOption() { return PrefixInformationOption.build( - new IpPrefix(SLAAC_PREFIX.getAddress(), SLAAC_PREFIX.getPrefixLength()), - (byte) (PIO_FLAG_ON_LINK | PIO_FLAG_AUTONOMOUS), 3600/*valid lifetime*/, - 3600/*preferred lifetime*/); + mPrefix, (byte) (PIO_FLAG_ON_LINK | PIO_FLAG_AUTONOMOUS), + 3600 /* valid lifetime */, 3600 /* preferred lifetime */); } private ByteBuffer buildRdnssOption() { @@ -105,19 +141,59 @@ public class RouterAdvertisementResponder extends PacketResponder { 0/*retransTimer, unspecified*/, buildPrefixOption(), buildRdnssOption()); } + private static void sendResponse(TapPacketReader reader, ByteBuffer buffer) { + try { + reader.sendResponse(buffer); + } catch (IOException e) { + throw new RuntimeException("Failed to send buffer."); + } + } + + private void replyToRouterSolicitation(TapPacketReader reader, MacAddress dstMac) { + for (Map.Entry<Inet6Address, Pair<MacAddress, Boolean>> it : mNeighborMap.entrySet()) { + final boolean isRouter = it.getValue().second; + if (!isRouter) { + continue; + } + final ByteBuffer raResponse = buildRaPacket(it.getValue().first, dstMac, it.getKey()); + sendResponse(reader, raResponse); + } + } + + private void replyToNeighborSolicitation(TapPacketReader reader, MacAddress dstMac, + Inet6Address dstIp, Inet6Address targetIp) { + final Pair<MacAddress, Boolean> neighbor = mNeighborMap.get(targetIp); + if (neighbor == null) { + return; + } + + final MacAddress srcMac = neighbor.first; + final boolean isRouter = neighbor.second; + int flags = NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED | NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE; + if (isRouter) { + flags |= NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER; + } + + final ByteBuffer tlla = LlaOption.build((byte) ICMPV6_ND_OPTION_TLLA, srcMac); + final ByteBuffer naResponse = Ipv6Utils.buildNaPacket(srcMac, dstMac, targetIp, dstIp, + flags, targetIp, tlla); + sendResponse(reader, naResponse); + } + @Override protected void replyToPacket(byte[] packet, TapPacketReader reader) { - final MacAddress srcMac = MacAddress.fromBytes( - Arrays.copyOfRange(packet, ETHER_SRC_ADDR_OFFSET, - ETHER_SRC_ADDR_OFFSET + ETHER_ADDR_LEN)); - - for (Pair<MacAddress, Inet6Address> it : mRouterList) { - final ByteBuffer raResponse = buildRaPacket(it.first, srcMac, it.second); - try { - reader.sendResponse(raResponse); - } catch (IOException e) { - throw new RuntimeException("Failed to send RA"); - } + final ByteBuffer buf = ByteBuffer.wrap(packet); + // Messages are filtered by parent class, so it is safe to assume that packet is either an + // RS or NS. + final EthernetHeader ethHdr = Struct.parse(EthernetHeader.class, buf); + final Ipv6Header ipv6Hdr = Struct.parse(Ipv6Header.class, buf); + final Icmpv6Header icmpv6Header = Struct.parse(Icmpv6Header.class, buf); + + if (icmpv6Header.type == ICMPV6_ROUTER_SOLICITATION) { + replyToRouterSolicitation(reader, ethHdr.srcMac); + } else if (icmpv6Header.type == ICMPV6_NEIGHBOR_SOLICITATION) { + final NsHeader nsHeader = Struct.parse(NsHeader.class, buf); + replyToNeighborSolicitation(reader, ethHdr.srcMac, ipv6Hdr.srcIp, nsHeader.target); } } } |