Merge changes from topic "nat64-integration-test-case" into main
* changes: [Thread] add an integration test case for NAT64 [Thread] support polling IPv4 packets in integration test
This commit is contained in:
commit
bf52fa708e
4 changed files with 187 additions and 61 deletions
|
|
@ -17,17 +17,20 @@
|
|||
package android.net.thread;
|
||||
|
||||
import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
|
||||
import static android.net.InetAddresses.parseNumericAddress;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.DEFAULT_DATASET;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.getIpv6LinkAddresses;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.isExpectedIcmpv4Packet;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.isExpectedIcmpv6Packet;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.isFromIpv6Source;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.isFrom;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.isInMulticastGroup;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.isToIpv6Destination;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.isTo;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.joinNetworkAndWaitForOmr;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.newPacketReader;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.pollForPacket;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.sendUdpMessage;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.waitFor;
|
||||
import static android.system.OsConstants.ICMP_ECHO;
|
||||
|
||||
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REPLY_TYPE;
|
||||
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
|
||||
|
|
@ -44,11 +47,11 @@ import static org.junit.Assert.assertNull;
|
|||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.InetAddresses;
|
||||
import android.net.IpPrefix;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.MacAddress;
|
||||
import android.net.RouteInfo;
|
||||
import android.net.thread.utils.FullThreadDevice;
|
||||
import android.net.thread.utils.InfraNetworkDevice;
|
||||
import android.net.thread.utils.OtDaemonController;
|
||||
|
|
@ -74,7 +77,9 @@ import org.junit.Rule;
|
|||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -89,11 +94,14 @@ public class BorderRoutingTest {
|
|||
private static final String TAG = BorderRoutingTest.class.getSimpleName();
|
||||
private static final int NUM_FTD = 2;
|
||||
private static final Inet6Address GROUP_ADDR_SCOPE_5 =
|
||||
(Inet6Address) InetAddresses.parseNumericAddress("ff05::1234");
|
||||
(Inet6Address) parseNumericAddress("ff05::1234");
|
||||
private static final Inet6Address GROUP_ADDR_SCOPE_4 =
|
||||
(Inet6Address) InetAddresses.parseNumericAddress("ff04::1234");
|
||||
(Inet6Address) parseNumericAddress("ff04::1234");
|
||||
private static final Inet6Address GROUP_ADDR_SCOPE_3 =
|
||||
(Inet6Address) InetAddresses.parseNumericAddress("ff03::1234");
|
||||
(Inet6Address) parseNumericAddress("ff03::1234");
|
||||
private static final Inet4Address IPV4_SERVER_ADDR =
|
||||
(Inet4Address) parseNumericAddress("8.8.8.8");
|
||||
private static final String NAT64_CIDR = "192.168.255.0/24";
|
||||
|
||||
@Rule public final ThreadFeatureCheckerRule mThreadRule = new ThreadFeatureCheckerRule();
|
||||
|
||||
|
|
@ -165,7 +173,7 @@ public class BorderRoutingTest {
|
|||
mInfraDevice.sendEchoRequest(ftd.getOmrAddress());
|
||||
|
||||
// Infra device receives an echo reply sent by FTD.
|
||||
assertNotNull(pollForPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd.getOmrAddress()));
|
||||
assertNotNull(pollForIcmpPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd.getOmrAddress()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -186,7 +194,7 @@ public class BorderRoutingTest {
|
|||
|
||||
mInfraDevice.sendEchoRequest(ftd.getOmrAddress());
|
||||
|
||||
assertNotNull(pollForPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd.getOmrAddress()));
|
||||
assertNotNull(pollForIcmpPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd.getOmrAddress()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -213,7 +221,7 @@ public class BorderRoutingTest {
|
|||
|
||||
mInfraDevice.sendEchoRequest(ftd.getOmrAddress());
|
||||
|
||||
assertNotNull(pollForPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftdOmr));
|
||||
assertNotNull(pollForIcmpPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftdOmr));
|
||||
} finally {
|
||||
runAsShell(MANAGE_TEST_NETWORKS, () -> oldInfraNetworkTracker.teardown());
|
||||
}
|
||||
|
|
@ -322,7 +330,7 @@ public class BorderRoutingTest {
|
|||
|
||||
mInfraDevice.sendEchoRequest(GROUP_ADDR_SCOPE_5);
|
||||
|
||||
assertNotNull(pollForPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd.getOmrAddress()));
|
||||
assertNotNull(pollForIcmpPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd.getOmrAddress()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -354,7 +362,7 @@ public class BorderRoutingTest {
|
|||
|
||||
mInfraDevice.sendEchoRequest(GROUP_ADDR_SCOPE_3);
|
||||
|
||||
assertNull(pollForPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd.getOmrAddress()));
|
||||
assertNull(pollForIcmpPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd.getOmrAddress()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -375,7 +383,7 @@ public class BorderRoutingTest {
|
|||
|
||||
mInfraDevice.sendEchoRequest(GROUP_ADDR_SCOPE_4);
|
||||
|
||||
assertNull(pollForPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd.getOmrAddress()));
|
||||
assertNull(pollForIcmpPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd.getOmrAddress()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -405,13 +413,15 @@ public class BorderRoutingTest {
|
|||
|
||||
mInfraDevice.sendEchoRequest(GROUP_ADDR_SCOPE_5);
|
||||
|
||||
assertNotNull(pollForPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd1.getOmrAddress()));
|
||||
assertNotNull(
|
||||
pollForIcmpPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd1.getOmrAddress()));
|
||||
|
||||
// Verify ping reply from ftd1 and ftd2 separately as the order of replies can't be
|
||||
// predicted.
|
||||
mInfraDevice.sendEchoRequest(GROUP_ADDR_SCOPE_4);
|
||||
|
||||
assertNotNull(pollForPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd2.getOmrAddress()));
|
||||
assertNotNull(
|
||||
pollForIcmpPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd2.getOmrAddress()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -441,12 +451,14 @@ public class BorderRoutingTest {
|
|||
|
||||
mInfraDevice.sendEchoRequest(GROUP_ADDR_SCOPE_5);
|
||||
|
||||
assertNotNull(pollForPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd1.getOmrAddress()));
|
||||
assertNotNull(
|
||||
pollForIcmpPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd1.getOmrAddress()));
|
||||
|
||||
// Send the request twice as the order of replies from ftd1 and ftd2 are not guaranteed
|
||||
mInfraDevice.sendEchoRequest(GROUP_ADDR_SCOPE_5);
|
||||
|
||||
assertNotNull(pollForPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd2.getOmrAddress()));
|
||||
assertNotNull(
|
||||
pollForIcmpPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftd2.getOmrAddress()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -469,9 +481,11 @@ public class BorderRoutingTest {
|
|||
ftd.ping(GROUP_ADDR_SCOPE_4);
|
||||
|
||||
assertNotNull(
|
||||
pollForPacketOnInfraNetwork(ICMPV6_ECHO_REQUEST_TYPE, ftdOmr, GROUP_ADDR_SCOPE_5));
|
||||
pollForIcmpPacketOnInfraNetwork(
|
||||
ICMPV6_ECHO_REQUEST_TYPE, ftdOmr, GROUP_ADDR_SCOPE_5));
|
||||
assertNotNull(
|
||||
pollForPacketOnInfraNetwork(ICMPV6_ECHO_REQUEST_TYPE, ftdOmr, GROUP_ADDR_SCOPE_4));
|
||||
pollForIcmpPacketOnInfraNetwork(
|
||||
ICMPV6_ECHO_REQUEST_TYPE, ftdOmr, GROUP_ADDR_SCOPE_4));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -493,7 +507,7 @@ public class BorderRoutingTest {
|
|||
ftd.ping(GROUP_ADDR_SCOPE_3);
|
||||
|
||||
assertNull(
|
||||
pollForPacketOnInfraNetwork(
|
||||
pollForIcmpPacketOnInfraNetwork(
|
||||
ICMPV6_ECHO_REQUEST_TYPE, ftd.getOmrAddress(), GROUP_ADDR_SCOPE_3));
|
||||
}
|
||||
|
||||
|
|
@ -517,7 +531,8 @@ public class BorderRoutingTest {
|
|||
ftd.ping(GROUP_ADDR_SCOPE_4, ftdLla);
|
||||
|
||||
assertNull(
|
||||
pollForPacketOnInfraNetwork(ICMPV6_ECHO_REQUEST_TYPE, ftdLla, GROUP_ADDR_SCOPE_4));
|
||||
pollForIcmpPacketOnInfraNetwork(
|
||||
ICMPV6_ECHO_REQUEST_TYPE, ftdLla, GROUP_ADDR_SCOPE_4));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -541,7 +556,7 @@ public class BorderRoutingTest {
|
|||
ftd.ping(GROUP_ADDR_SCOPE_4, ftdMla);
|
||||
|
||||
assertNull(
|
||||
pollForPacketOnInfraNetwork(
|
||||
pollForIcmpPacketOnInfraNetwork(
|
||||
ICMPV6_ECHO_REQUEST_TYPE, ftdMla, GROUP_ADDR_SCOPE_4));
|
||||
}
|
||||
}
|
||||
|
|
@ -572,7 +587,7 @@ public class BorderRoutingTest {
|
|||
|
||||
mInfraDevice.sendEchoRequest(GROUP_ADDR_SCOPE_5);
|
||||
|
||||
assertNotNull(pollForPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftdOmr));
|
||||
assertNotNull(pollForIcmpPacketOnInfraNetwork(ICMPV6_ECHO_REPLY_TYPE, ftdOmr));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -600,18 +615,40 @@ public class BorderRoutingTest {
|
|||
ftd.ping(GROUP_ADDR_SCOPE_4);
|
||||
|
||||
assertNotNull(
|
||||
pollForPacketOnInfraNetwork(ICMPV6_ECHO_REQUEST_TYPE, ftdOmr, GROUP_ADDR_SCOPE_4));
|
||||
pollForIcmpPacketOnInfraNetwork(
|
||||
ICMPV6_ECHO_REQUEST_TYPE, ftdOmr, GROUP_ADDR_SCOPE_4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nat64_threadDevicePingIpv4InfraDevice_outboundPacketIsForwarded() throws Exception {
|
||||
FullThreadDevice ftd = mFtds.get(0);
|
||||
joinNetworkAndWaitForOmr(ftd, DEFAULT_DATASET);
|
||||
// TODO: enable NAT64 via ThreadNetworkController API instead of ot-ctl
|
||||
mOtCtl.setNat64Cidr(NAT64_CIDR);
|
||||
mOtCtl.setNat64Enabled(true);
|
||||
waitFor(() -> mOtCtl.hasNat64PrefixInNetdata(), Duration.ofSeconds(10));
|
||||
|
||||
ftd.ping(IPV4_SERVER_ADDR);
|
||||
|
||||
assertNotNull(pollForIcmpPacketOnInfraNetwork(ICMP_ECHO, null, IPV4_SERVER_ADDR));
|
||||
}
|
||||
|
||||
private void setUpInfraNetwork() throws Exception {
|
||||
LinkProperties lp = new LinkProperties();
|
||||
// NAT64 feature requires the infra network to have an IPv4 default route.
|
||||
lp.addRoute(
|
||||
new RouteInfo(
|
||||
new IpPrefix("0.0.0.0/0") /* destination */,
|
||||
null /* gateway */,
|
||||
null,
|
||||
RouteInfo.RTN_UNICAST,
|
||||
1500 /* mtu */));
|
||||
mInfraNetworkTracker =
|
||||
runAsShell(
|
||||
MANAGE_TEST_NETWORKS,
|
||||
() ->
|
||||
initTestNetwork(
|
||||
mContext, new LinkProperties(), 5000 /* timeoutMs */));
|
||||
mController.setTestNetworkAsUpstreamAndWait(
|
||||
mInfraNetworkTracker.getTestIface().getInterfaceName());
|
||||
() -> initTestNetwork(mContext, lp, 5000 /* timeoutMs */));
|
||||
String infraNetworkName = mInfraNetworkTracker.getTestIface().getInterfaceName();
|
||||
mController.setTestNetworkAsUpstreamAndWait(infraNetworkName);
|
||||
}
|
||||
|
||||
private void tearDownInfraNetwork() {
|
||||
|
|
@ -648,20 +685,28 @@ public class BorderRoutingTest {
|
|||
assertInfraLinkMemberOfGroup(address);
|
||||
}
|
||||
|
||||
private byte[] pollForPacketOnInfraNetwork(int type, Inet6Address srcAddress) {
|
||||
return pollForPacketOnInfraNetwork(type, srcAddress, null);
|
||||
private byte[] pollForIcmpPacketOnInfraNetwork(int type, InetAddress srcAddress) {
|
||||
return pollForIcmpPacketOnInfraNetwork(type, srcAddress, null /* destAddress */);
|
||||
}
|
||||
|
||||
private byte[] pollForPacketOnInfraNetwork(
|
||||
int type, Inet6Address srcAddress, Inet6Address destAddress) {
|
||||
Predicate<byte[]> filter;
|
||||
filter =
|
||||
private byte[] pollForIcmpPacketOnInfraNetwork(
|
||||
int type, InetAddress srcAddress, InetAddress destAddress) {
|
||||
if (srcAddress == null && destAddress == null) {
|
||||
throw new IllegalArgumentException("srcAddress and destAddress cannot be both null");
|
||||
}
|
||||
if (srcAddress != null && destAddress != null) {
|
||||
if ((srcAddress instanceof Inet4Address) != (destAddress instanceof Inet4Address)) {
|
||||
throw new IllegalArgumentException(
|
||||
"srcAddress and destAddress must be both IPv4 or both IPv6");
|
||||
}
|
||||
}
|
||||
boolean isIpv4 =
|
||||
(srcAddress instanceof Inet4Address) || (destAddress instanceof Inet4Address);
|
||||
final Predicate<byte[]> filter =
|
||||
p ->
|
||||
(isExpectedIcmpv6Packet(p, type)
|
||||
&& (srcAddress == null ? true : isFromIpv6Source(p, srcAddress))
|
||||
&& (destAddress == null
|
||||
? true
|
||||
: isToIpv6Destination(p, destAddress)));
|
||||
(isIpv4 ? isExpectedIcmpv4Packet(p, type) : isExpectedIcmpv6Packet(p, type))
|
||||
&& (srcAddress == null || isFrom(p, srcAddress))
|
||||
&& (destAddress == null || isTo(p, destAddress));
|
||||
return pollForPacket(mInfraNetworkReader, filter);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -417,7 +417,7 @@ public final class FullThreadDevice {
|
|||
executeCommand("ipmaddr add " + address.getHostAddress());
|
||||
}
|
||||
|
||||
public void ping(Inet6Address address, Inet6Address source) {
|
||||
public void ping(InetAddress address, Inet6Address source) {
|
||||
ping(
|
||||
address,
|
||||
source,
|
||||
|
|
@ -428,7 +428,7 @@ public final class FullThreadDevice {
|
|||
PING_TIMEOUT_0_1_SECOND);
|
||||
}
|
||||
|
||||
public void ping(Inet6Address address) {
|
||||
public void ping(InetAddress address) {
|
||||
ping(
|
||||
address,
|
||||
null,
|
||||
|
|
@ -440,7 +440,7 @@ public final class FullThreadDevice {
|
|||
}
|
||||
|
||||
/** Returns the number of ping reply packets received. */
|
||||
public int ping(Inet6Address address, int count) {
|
||||
public int ping(InetAddress address, int count) {
|
||||
List<String> output =
|
||||
ping(
|
||||
address,
|
||||
|
|
@ -454,7 +454,7 @@ public final class FullThreadDevice {
|
|||
}
|
||||
|
||||
private List<String> ping(
|
||||
Inet6Address address,
|
||||
InetAddress address,
|
||||
Inet6Address source,
|
||||
int size,
|
||||
int count,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
package android.net.thread.utils;
|
||||
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK;
|
||||
import static android.system.OsConstants.IPPROTO_ICMP;
|
||||
import static android.system.OsConstants.IPPROTO_ICMPV6;
|
||||
|
||||
import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
|
||||
|
|
@ -49,7 +50,9 @@ import androidx.annotation.NonNull;
|
|||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import com.android.net.module.util.Struct;
|
||||
import com.android.net.module.util.structs.Icmpv4Header;
|
||||
import com.android.net.module.util.structs.Icmpv6Header;
|
||||
import com.android.net.module.util.structs.Ipv4Header;
|
||||
import com.android.net.module.util.structs.Ipv6Header;
|
||||
import com.android.net.module.util.structs.PrefixInformationOption;
|
||||
import com.android.net.module.util.structs.RaHeader;
|
||||
|
|
@ -62,6 +65,7 @@ import java.io.FileDescriptor;
|
|||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
|
|
@ -192,16 +196,36 @@ public final class IntegrationTestUtils {
|
|||
return null;
|
||||
}
|
||||
|
||||
/** Returns {@code true} if {@code packet} is an ICMPv4 packet of given {@code type}. */
|
||||
public static boolean isExpectedIcmpv4Packet(byte[] packet, int type) {
|
||||
ByteBuffer buf = makeByteBuffer(packet);
|
||||
Ipv4Header header = extractIpv4Header(buf);
|
||||
if (header == null) {
|
||||
return false;
|
||||
}
|
||||
if (header.protocol != (byte) IPPROTO_ICMP) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return Struct.parse(Icmpv4Header.class, buf).type == (short) type;
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// It's fine that the passed in packet is malformed because it's could be sent
|
||||
// by anybody.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns {@code true} if {@code packet} is an ICMPv6 packet of given {@code type}. */
|
||||
public static boolean isExpectedIcmpv6Packet(byte[] packet, int type) {
|
||||
if (packet == null) {
|
||||
ByteBuffer buf = makeByteBuffer(packet);
|
||||
Ipv6Header header = extractIpv6Header(buf);
|
||||
if (header == null) {
|
||||
return false;
|
||||
}
|
||||
if (header.nextHeader != (byte) IPPROTO_ICMPV6) {
|
||||
return false;
|
||||
}
|
||||
ByteBuffer buf = ByteBuffer.wrap(packet);
|
||||
try {
|
||||
if (Struct.parse(Ipv6Header.class, buf).nextHeader != (byte) IPPROTO_ICMPV6) {
|
||||
return false;
|
||||
}
|
||||
return Struct.parse(Icmpv6Header.class, buf).type == (short) type;
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// It's fine that the passed in packet is malformed because it's could be sent
|
||||
|
|
@ -210,32 +234,66 @@ public final class IntegrationTestUtils {
|
|||
return false;
|
||||
}
|
||||
|
||||
public static boolean isFromIpv6Source(byte[] packet, Inet6Address src) {
|
||||
if (packet == null) {
|
||||
return false;
|
||||
}
|
||||
ByteBuffer buf = ByteBuffer.wrap(packet);
|
||||
try {
|
||||
return Struct.parse(Ipv6Header.class, buf).srcIp.equals(src);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// It's fine that the passed in packet is malformed because it's could be sent
|
||||
// by anybody.
|
||||
public static boolean isFrom(byte[] packet, InetAddress src) {
|
||||
if (src instanceof Inet4Address) {
|
||||
return isFromIpv4Source(packet, (Inet4Address) src);
|
||||
} else if (src instanceof Inet6Address) {
|
||||
return isFromIpv6Source(packet, (Inet6Address) src);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isToIpv6Destination(byte[] packet, Inet6Address dest) {
|
||||
if (packet == null) {
|
||||
return false;
|
||||
public static boolean isTo(byte[] packet, InetAddress dest) {
|
||||
if (dest instanceof Inet4Address) {
|
||||
return isToIpv4Destination(packet, (Inet4Address) dest);
|
||||
} else if (dest instanceof Inet6Address) {
|
||||
return isToIpv6Destination(packet, (Inet6Address) dest);
|
||||
}
|
||||
ByteBuffer buf = ByteBuffer.wrap(packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isFromIpv4Source(byte[] packet, Inet4Address src) {
|
||||
Ipv4Header header = extractIpv4Header(makeByteBuffer(packet));
|
||||
return header != null && header.srcIp.equals(src);
|
||||
}
|
||||
|
||||
private static boolean isFromIpv6Source(byte[] packet, Inet6Address src) {
|
||||
Ipv6Header header = extractIpv6Header(makeByteBuffer(packet));
|
||||
return header != null && header.srcIp.equals(src);
|
||||
}
|
||||
|
||||
private static boolean isToIpv4Destination(byte[] packet, Inet4Address dest) {
|
||||
Ipv4Header header = extractIpv4Header(makeByteBuffer(packet));
|
||||
return header != null && header.dstIp.equals(dest);
|
||||
}
|
||||
|
||||
private static boolean isToIpv6Destination(byte[] packet, Inet6Address dest) {
|
||||
Ipv6Header header = extractIpv6Header(makeByteBuffer(packet));
|
||||
return header != null && header.dstIp.equals(dest);
|
||||
}
|
||||
|
||||
private static ByteBuffer makeByteBuffer(byte[] packet) {
|
||||
return packet == null ? null : ByteBuffer.wrap(packet);
|
||||
}
|
||||
|
||||
private static Ipv4Header extractIpv4Header(ByteBuffer buf) {
|
||||
try {
|
||||
return Struct.parse(Ipv6Header.class, buf).dstIp.equals(dest);
|
||||
return Struct.parse(Ipv4Header.class, buf);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// It's fine that the passed in packet is malformed because it's could be sent
|
||||
// by anybody.
|
||||
}
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Ipv6Header extractIpv6Header(ByteBuffer buf) {
|
||||
try {
|
||||
return Struct.parse(Ipv6Header.class, buf);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// It's fine that the passed in packet is malformed because it's could be sent
|
||||
// by anybody.
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Returns the Prefix Information Options (PIO) extracted from an ICMPv6 RA message. */
|
||||
|
|
|
|||
|
|
@ -105,6 +105,29 @@ public final class OtDaemonController {
|
|||
return prefixes.isEmpty() ? null : prefixes.get(0);
|
||||
}
|
||||
|
||||
/** Enables/Disables NAT64 feature. */
|
||||
public void setNat64Enabled(boolean enabled) {
|
||||
executeCommand("nat64 " + (enabled ? "enable" : "disable"));
|
||||
}
|
||||
|
||||
/** Sets the NAT64 CIDR. */
|
||||
public void setNat64Cidr(String cidr) {
|
||||
executeCommand("nat64 cidr " + cidr);
|
||||
}
|
||||
|
||||
/** Returns whether there's a NAT64 prefix in network data */
|
||||
public boolean hasNat64PrefixInNetdata() {
|
||||
// Example (in the 'Routes' section):
|
||||
// fdb2:bae3:5b59:2:0:0::/96 sn low c000
|
||||
List<String> outputLines = executeCommandAndParse("netdata show");
|
||||
for (String line : outputLines) {
|
||||
if (line.contains(" sn")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String executeCommand(String cmd) {
|
||||
return SystemUtil.runShellCommand(OT_CTL + " " + cmd);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue