Test TCP and ICMPv6 on VPNs in addition to UDP.
Bug: 15605143
Change-Id: Ifd7a646990619057e714a789902df2c157a768c0
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/MyVpnService.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/MyVpnService.java
index 1a12aaa..a3f400c 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/MyVpnService.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/MyVpnService.java
@@ -34,7 +34,7 @@
private static int MTU = 1799;
private ParcelFileDescriptor mFd = null;
- private UdpReflector mUdpReflector = null;
+ private PacketReflector mPacketReflector = null;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
@@ -127,14 +127,14 @@
mFd = builder.establish();
Log.i(TAG, "Established, fd=" + (mFd == null ? "null" : mFd.getFd()));
- mUdpReflector = new UdpReflector(mFd.getFileDescriptor(), MTU);
- mUdpReflector.start();
+ mPacketReflector = new PacketReflector(mFd.getFileDescriptor(), MTU);
+ mPacketReflector.start();
}
private void stop() {
- if (mUdpReflector != null) {
- mUdpReflector.interrupt();
- mUdpReflector = null;
+ if (mPacketReflector != null) {
+ mPacketReflector.interrupt();
+ mPacketReflector = null;
}
try {
if (mFd != null) {
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/PacketReflector.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/PacketReflector.java
new file mode 100644
index 0000000..dd0f792
--- /dev/null
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/PacketReflector.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2014 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.cts.net.hostside;
+
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+public class PacketReflector extends Thread {
+
+ private static int IPV4_HEADER_LENGTH = 20;
+ private static int IPV6_HEADER_LENGTH = 40;
+
+ private static int IPV4_ADDR_OFFSET = 12;
+ private static int IPV6_ADDR_OFFSET = 8;
+ private static int IPV4_ADDR_LENGTH = 4;
+ private static int IPV6_ADDR_LENGTH = 16;
+
+ private static int IPV4_PROTO_OFFSET = 9;
+ private static int IPV6_PROTO_OFFSET = 6;
+
+ private static final byte IPPROTO_ICMP = 1;
+ private static final byte IPPROTO_TCP = 6;
+ private static final byte IPPROTO_UDP = 17;
+ private static final byte IPPROTO_ICMPV6 = 58;
+
+ private static int ICMP_HEADER_LENGTH = 8;
+ private static int TCP_HEADER_LENGTH = 20;
+ private static int UDP_HEADER_LENGTH = 8;
+
+ private static final byte ICMP_ECHO = 8;
+ private static final byte ICMP_ECHOREPLY = 0;
+ private static final byte ICMPV6_ECHO_REQUEST = (byte) 128;
+ private static final byte ICMPV6_ECHO_REPLY = (byte) 129;
+
+ private static String TAG = "PacketReflector";
+
+ private FileDescriptor mFd;
+ private byte[] mBuf;
+
+ public PacketReflector(FileDescriptor fd, int mtu) {
+ super("PacketReflector");
+ mFd = fd;
+ mBuf = new byte[mtu];
+ }
+
+ private static void swapBytes(byte[] buf, int pos1, int pos2, int len) {
+ for (int i = 0; i < len; i++) {
+ byte b = buf[pos1 + i];
+ buf[pos1 + i] = buf[pos2 + i];
+ buf[pos2 + i] = b;
+ }
+ }
+
+ private static void swapAddresses(byte[] buf, int version) {
+ int addrPos, addrLen;
+ switch(version) {
+ case 4:
+ addrPos = IPV4_ADDR_OFFSET;
+ addrLen = IPV4_ADDR_LENGTH;
+ break;
+ case 6:
+ addrPos = IPV6_ADDR_OFFSET;
+ addrLen = IPV6_ADDR_LENGTH;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ swapBytes(buf, addrPos, addrPos + addrLen, addrLen);
+ }
+
+ // Reflect TCP packets: swap the source and destination addresses, but don't change the ports.
+ // This is used by the test to "connect to itself" through the VPN.
+ private void processTcpPacket(byte[] buf, int version, int len, int hdrLen) {
+ if (len < hdrLen + TCP_HEADER_LENGTH) {
+ return;
+ }
+
+ // Swap src and dst IP addresses.
+ swapAddresses(buf, version);
+
+ // Send the packet back.
+ writePacket(buf, len);
+ }
+
+ // Echo UDP packets: swap source and destination addresses, and source and destination ports.
+ // This is used by the test to check that the bytes it sends are echoed back.
+ private void processUdpPacket(byte[] buf, int version, int len, int hdrLen) {
+ if (len < hdrLen + UDP_HEADER_LENGTH) {
+ return;
+ }
+
+ // Swap src and dst IP addresses.
+ swapAddresses(buf, version);
+
+ // Swap dst and src ports.
+ int portOffset = hdrLen;
+ swapBytes(buf, portOffset, portOffset + 2, 2);
+
+ // Send the packet back.
+ writePacket(buf, len);
+ }
+
+ private void processIcmpPacket(byte[] buf, int version, int len, int hdrLen) {
+ if (len < hdrLen + ICMP_HEADER_LENGTH) {
+ return;
+ }
+
+ byte type = buf[hdrLen];
+ if (!(version == 4 && type == ICMP_ECHO) &&
+ !(version == 6 && type == ICMPV6_ECHO_REQUEST)) {
+ return;
+ }
+
+ // Save the ping packet we received.
+ byte[] request = buf.clone();
+
+ // Swap src and dst IP addresses, and send the packet back.
+ // This effectively pings the device to see if it replies.
+ swapAddresses(buf, version);
+ writePacket(buf, len);
+
+ // The device should have replied, and buf should now contain a ping response.
+ int received = readPacket(buf);
+ if (received != len) {
+ Log.i(TAG, "Reflecting ping did not result in ping response: " +
+ "read=" + received + " expected=" + len);
+ return;
+ }
+
+ // Compare the response we got with the original packet.
+ // The only thing that should have changed are addresses, type and checksum.
+ // Overwrite them with the received bytes and see if the packet is otherwise identical.
+ request[hdrLen] = buf[hdrLen]; // Type.
+ request[hdrLen + 2] = buf[hdrLen + 2]; // Checksum byte 1.
+ request[hdrLen + 3] = buf[hdrLen + 3]; // Checksum byte 2.
+ for (int i = 0; i < len; i++) {
+ if (buf[i] != request[i]) {
+ Log.i(TAG, "Received non-matching packet when expecting ping response.");
+ return;
+ }
+ }
+
+ // Now swap the addresses again and reflect the packet. This sends a ping reply.
+ swapAddresses(buf, version);
+ writePacket(buf, len);
+ }
+
+ private void writePacket(byte[] buf, int len) {
+ try {
+ Os.write(mFd, buf, 0, len);
+ } catch (ErrnoException|IOException e) {
+ Log.e(TAG, "Error writing packet: " + e.getMessage());
+ }
+ }
+
+ private int readPacket(byte[] buf) {
+ int len;
+ try {
+ len = Os.read(mFd, buf, 0, buf.length);
+ } catch (ErrnoException|IOException e) {
+ Log.e(TAG, "Error reading packet: " + e.getMessage());
+ len = -1;
+ }
+ return len;
+ }
+
+ // Reads one packet from our mFd, and possibly writes the packet back.
+ private void processPacket() {
+ int len = readPacket(mBuf);
+ if (len < 1) {
+ return;
+ }
+
+ int version = mBuf[0] >> 4;
+ int addrPos, protoPos, hdrLen, addrLen;
+ if (version == 4) {
+ hdrLen = IPV4_HEADER_LENGTH;
+ protoPos = IPV4_PROTO_OFFSET;
+ addrPos = IPV4_ADDR_OFFSET;
+ addrLen = IPV4_ADDR_LENGTH;
+ } else if (version == 6) {
+ hdrLen = IPV6_HEADER_LENGTH;
+ protoPos = IPV6_PROTO_OFFSET;
+ addrPos = IPV6_ADDR_OFFSET;
+ addrLen = IPV6_ADDR_LENGTH;
+ } else {
+ return;
+ }
+
+ if (len < hdrLen) {
+ return;
+ }
+
+ byte proto = mBuf[protoPos];
+ switch (proto) {
+ case IPPROTO_ICMP:
+ case IPPROTO_ICMPV6:
+ processIcmpPacket(mBuf, version, len, hdrLen);
+ break;
+ case IPPROTO_TCP:
+ processTcpPacket(mBuf, version, len, hdrLen);
+ break;
+ case IPPROTO_UDP:
+ processUdpPacket(mBuf, version, len, hdrLen);
+ break;
+ }
+ }
+
+ public void run() {
+ Log.i(TAG, "PacketReflector starting fd=" + mFd + " valid=" + mFd.valid());
+ while (!interrupted() && mFd.valid()) {
+ processPacket();
+ }
+ Log.i(TAG, "PacketReflector exiting fd=" + mFd + " valid=" + mFd.valid());
+ }
+}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/UdpReflector.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/UdpReflector.java
deleted file mode 100644
index a730fed..0000000
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/UdpReflector.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2014 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.cts.net.hostside;
-
-import android.system.Os;
-import android.system.ErrnoException;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-
-public class UdpReflector extends Thread {
-
- private static int IPV4_HEADER_LENGTH = 20;
- private static int IPV6_HEADER_LENGTH = 40;
- private static int UDP_HEADER_LENGTH = 8;
-
- private static int IPV4_PROTO_OFFSET = 9;
- private static int IPV6_PROTO_OFFSET = 6;
- private static int IPPROTO_UDP = 17;
-
- private static int IPV4_ADDR_OFFSET = 12;
- private static int IPV6_ADDR_OFFSET = 8;
- private static int IPV4_ADDR_LENGTH = 4;
- private static int IPV6_ADDR_LENGTH = 16;
-
- private static String TAG = "UdpReflector";
-
- private FileDescriptor mFd;
- private byte[] mBuf;
-
- public UdpReflector(FileDescriptor fd, int mtu) {
- super("UdpReflector");
- mFd = fd;
- mBuf = new byte[mtu];
- }
-
- private static void swapBytes(byte[] buf, int pos1, int pos2, int len) {
- for (int i = 0; i < len; i++) {
- byte b = buf[pos1 + i];
- buf[pos1 + i] = buf[pos2 + i];
- buf[pos2 + i] = b;
- }
- }
-
- /** Reads one packet from our mFd, and possibly writes the packet back. */
- private void processPacket() {
- int len;
- try {
- len = Os.read(mFd, mBuf, 0, mBuf.length);
- } catch (ErrnoException|IOException e) {
- Log.e(TAG, "Error reading packet: " + e.getMessage());
- return;
- }
-
- int version = mBuf[0] >> 4;
- int addressOffset, protoOffset, headerLength, addressLength;
- if (version == 4) {
- headerLength = IPV4_HEADER_LENGTH;
- protoOffset = IPV4_PROTO_OFFSET;
- addressOffset = IPV4_ADDR_OFFSET;
- addressLength = IPV4_ADDR_LENGTH;
- } else if (version == 6) {
- headerLength = IPV6_HEADER_LENGTH;
- protoOffset = IPV6_PROTO_OFFSET;
- addressOffset = IPV6_ADDR_OFFSET;
- addressLength = IPV6_ADDR_LENGTH;
- } else {
- return;
- }
-
- if (len < headerLength + UDP_HEADER_LENGTH || mBuf[protoOffset] != IPPROTO_UDP) {
- return;
- }
-
- // Swap src and dst IP addresses.
- swapBytes(mBuf, addressOffset, addressOffset + addressLength, addressLength);
-
- // Swap dst and src ports.
- int portOffset = headerLength;
- swapBytes(mBuf, portOffset, portOffset + 2, 2);
-
- // Send the packet back. We don't need to recalculate the checksum because we didn't change
- // the packet bytes, we only moved them around.
- try {
- len = Os.write(mFd, mBuf, 0, len);
- } catch (ErrnoException|IOException e) {
- Log.e(TAG, "Error writing packet: " + e.getMessage());
- }
- }
-
- public void run() {
- Log.i(TAG, "UdpReflector starting fd=" + mFd + " valid=" + mFd.valid());
- while (!interrupted() && mFd.valid()) {
- processPacket();
- }
- Log.i(TAG, "UdpReflector exiting fd=" + mFd + " valid=" + mFd.valid());
- }
-}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java
index cdd370e..8bb2a2c 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java
@@ -16,6 +16,8 @@
package com.android.cts.net.hostside;
+import static android.system.OsConstants.*;
+
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
@@ -25,34 +27,58 @@
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.VpnService;
-import android.os.ParcelFileDescriptor;
-import android.os.SystemClock;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiScrollable;
import android.support.test.uiautomator.UiSelector;
-import android.test.MoreAsserts;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructPollfd;
import android.test.InstrumentationTestCase;
+import android.test.MoreAsserts;
import android.text.TextUtils;
import android.util.Log;
+import java.io.Closeable;
+import java.io.FileDescriptor;
import java.io.IOException;
-import java.net.SocketTimeoutException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
-import java.net.InetAddress;
import java.net.Inet6Address;
-import java.util.concurrent.atomic.AtomicReference;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.Random;
/**
- * Tests for {@link DocumentsProvider} and interaction with platform intents
- * like {@link Intent#ACTION_OPEN_DOCUMENT}.
+ * Tests for the VpnService API.
+ *
+ * These tests establish a VPN via the VpnService API, and have the service reflect the packets back
+ * to the device without causing any network traffic. This allows testing the local VPN data path
+ * without a network connection or a VPN server.
+ *
+ * Note: in Lollipop, VPN functionality relies on kernel support for UID-based routing. If these
+ * tests fail, it may be due to the lack of kernel support. The necessary patches can be
+ * cherry-picked from the Android common kernel trees:
+ *
+ * android-3.10:
+ * https://android-review.googlesource.com/#/c/99220/
+ * https://android-review.googlesource.com/#/c/100545/
+ *
+ * android-3.4:
+ * https://android-review.googlesource.com/#/c/99225/
+ * https://android-review.googlesource.com/#/c/100557/
+ *
*/
public class VpnTest extends InstrumentationTestCase {
public static String TAG = "VpnTest";
public static int TIMEOUT_MS = 3 * 1000;
+ public static int SOCKET_TIMEOUT_MS = 100;
private UiDevice mDevice;
private MyActivity mActivity;
@@ -201,8 +227,156 @@
mActivity.startService(intent);
}
- private static void checkUdpEcho(
- String to, String expectedFrom, boolean expectReply) throws IOException {
+ private static void closeQuietly(Closeable c) {
+ if (c != null) {
+ try {
+ c.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ private static void checkPing(String to) throws IOException, ErrnoException {
+ InetAddress address = InetAddress.getByName(to);
+ FileDescriptor s;
+ final int LENGTH = 64;
+ byte[] packet = new byte[LENGTH];
+ byte[] header;
+
+ // Construct a ping packet.
+ Random random = new Random();
+ random.nextBytes(packet);
+ if (address instanceof Inet6Address) {
+ s = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
+ header = new byte[] { (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
+ } else {
+ // Note that this doesn't actually work due to http://b/18558481 .
+ s = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+ header = new byte[] { (byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
+ }
+ System.arraycopy(header, 0, packet, 0, header.length);
+
+ // Send the packet.
+ int port = random.nextInt(65534) + 1;
+ Os.connect(s, address, port);
+ Os.write(s, packet, 0, packet.length);
+
+ // Expect a reply.
+ StructPollfd pollfd = new StructPollfd();
+ pollfd.events = (short) POLLIN; // "error: possible loss of precision"
+ pollfd.fd = s;
+ int ret = Os.poll(new StructPollfd[] { pollfd }, SOCKET_TIMEOUT_MS);
+ assertEquals("Expected reply after sending ping", 1, ret);
+
+ byte[] reply = new byte[LENGTH];
+ int read = Os.read(s, reply, 0, LENGTH);
+ assertEquals(LENGTH, read);
+
+ // Find out what the kernel set the ICMP ID to.
+ InetSocketAddress local = (InetSocketAddress) Os.getsockname(s);
+ port = local.getPort();
+ packet[4] = (byte) ((port >> 8) & 0xff);
+ packet[5] = (byte) (port & 0xff);
+
+ // Check the contents.
+ if (packet[0] == (byte) 0x80) {
+ packet[0] = (byte) 0x81;
+ } else {
+ packet[0] = 0;
+ }
+ // Zero out the checksum in the reply so it matches the uninitialized checksum in packet.
+ reply[2] = reply[3] = 0;
+ MoreAsserts.assertEquals(packet, reply);
+ }
+
+ // Writes data to out and checks that it appears identically on in.
+ private static void writeAndCheckData(
+ OutputStream out, InputStream in, byte[] data) throws IOException {
+ out.write(data, 0, data.length);
+ out.flush();
+
+ byte[] read = new byte[data.length];
+ int bytesRead = 0, totalRead = 0;
+ do {
+ bytesRead = in.read(read, totalRead, read.length - totalRead);
+ totalRead += bytesRead;
+ } while (bytesRead >= 0 && totalRead < data.length);
+ assertEquals(totalRead, data.length);
+ MoreAsserts.assertEquals(data, read);
+ }
+
+ private static void checkTcpReflection(String to, String expectedFrom) throws IOException {
+ // Exercise TCP over the VPN by "connecting to ourselves". We open a server socket and a
+ // client socket, and connect the client socket to a remote host, with the port of the
+ // server socket. The PacketReflector reflects the packets, changing the source addresses
+ // but not the ports, so our client socket is connected to our server socket, though both
+ // sockets think their peers are on the "remote" IP address.
+
+ // Open a listening socket.
+ ServerSocket listen = new ServerSocket(0, 10, InetAddress.getByName("::"));
+
+ // Connect the client socket to it.
+ InetAddress toAddr = InetAddress.getByName(to);
+ Socket client = new Socket();
+ try {
+ client.connect(new InetSocketAddress(toAddr, listen.getLocalPort()), SOCKET_TIMEOUT_MS);
+ if (expectedFrom == null) {
+ closeQuietly(listen);
+ closeQuietly(client);
+ fail("Expected connection to fail, but it succeeded.");
+ }
+ } catch (IOException e) {
+ if (expectedFrom != null) {
+ closeQuietly(listen);
+ fail("Expected connection to succeed, but it failed.");
+ } else {
+ // We expected the connection to fail, and it did, so there's nothing more to test.
+ return;
+ }
+ }
+
+ // The connection succeeded, and we expected it to succeed. Send some data; if things are
+ // working, the data will be sent to the VPN, reflected by the PacketReflector, and arrive
+ // at our server socket. For good measure, send some data in the other direction.
+ Socket server = null;
+ try {
+ // Accept the connection on the server side.
+ listen.setSoTimeout(SOCKET_TIMEOUT_MS);
+ server = listen.accept();
+
+ // Check that the source and peer addresses are as expected.
+ assertEquals(expectedFrom, client.getLocalAddress().getHostAddress());
+ assertEquals(expectedFrom, server.getLocalAddress().getHostAddress());
+ assertEquals(
+ new InetSocketAddress(toAddr, client.getLocalPort()),
+ server.getRemoteSocketAddress());
+ assertEquals(
+ new InetSocketAddress(toAddr, server.getLocalPort()),
+ client.getRemoteSocketAddress());
+
+ // Now write some data.
+ final int LENGTH = 32768;
+ byte[] data = new byte[LENGTH];
+ new Random().nextBytes(data);
+
+ // Make sure our writes don't block or time out, because we're single-threaded and can't
+ // read and write at the same time.
+ server.setReceiveBufferSize(LENGTH * 2);
+ client.setSendBufferSize(LENGTH * 2);
+ client.setSoTimeout(SOCKET_TIMEOUT_MS);
+ server.setSoTimeout(SOCKET_TIMEOUT_MS);
+
+ // Send some data from client to server, then from server to client.
+ writeAndCheckData(client.getOutputStream(), server.getInputStream(), data);
+ writeAndCheckData(server.getOutputStream(), client.getInputStream(), data);
+ } finally {
+ closeQuietly(listen);
+ closeQuietly(client);
+ closeQuietly(server);
+ }
+ }
+
+ private static void checkUdpEcho(String to, String expectedFrom) throws IOException {
DatagramSocket s;
InetAddress address = InetAddress.getByName(to);
if (address instanceof Inet6Address) { // http://b/18094870
@@ -210,10 +384,12 @@
} else {
s = new DatagramSocket();
}
- s.setSoTimeout(100); // ms.
+ s.setSoTimeout(SOCKET_TIMEOUT_MS);
- String msg = "Hello, world!";
- DatagramPacket p = new DatagramPacket(msg.getBytes(), msg.length());
+ Random random = new Random();
+ byte[] data = new byte[random.nextInt(1650)];
+ random.nextBytes(data);
+ DatagramPacket p = new DatagramPacket(data, data.length);
s.connect(address, 7);
if (expectedFrom != null) {
@@ -222,10 +398,10 @@
}
try {
- if (expectReply) {
+ if (expectedFrom != null) {
s.send(p);
s.receive(p);
- MoreAsserts.assertEquals(msg.getBytes(), p.getData());
+ MoreAsserts.assertEquals(data, p.getData());
} else {
try {
s.send(p);
@@ -238,12 +414,19 @@
}
}
- private static void expectUdpEcho(String to, String expectedFrom) throws IOException {
- checkUdpEcho(to, expectedFrom, true);
+ private void checkTrafficOnVpn() throws IOException, ErrnoException {
+ checkUdpEcho("192.0.2.251", "192.0.2.2");
+ checkUdpEcho("2001:db8:dead:beef::f00", "2001:db8:1:2::ffe");
+ checkPing("2001:db8:dead:beef::f00");
+ checkTcpReflection("192.0.2.252", "192.0.2.2");
+ checkTcpReflection("2001:db8:dead:beef::f00", "2001:db8:1:2::ffe");
}
- private static void expectNoUdpEcho(String to) throws IOException {
- checkUdpEcho(to, null, false);
+ private void checkNoTrafficOnVpn() throws IOException, ErrnoException {
+ checkUdpEcho("192.0.2.251", null);
+ checkUdpEcho("2001:db8:dead:beef::f00", null);
+ checkTcpReflection("192.0.2.252", null);
+ checkTcpReflection("2001:db8:dead:beef::f00", null);
}
public void testDefault() throws Exception {
@@ -253,8 +436,7 @@
new String[] {"192.0.2.0/24", "2001:db8::/32"},
"", "");
- expectUdpEcho("192.0.2.251", "192.0.2.2");
- expectUdpEcho("2001:db8:dead:beef::f00", "2001:db8:1:2::ffe");
+ checkTrafficOnVpn();
}
public void testAppAllowed() throws Exception {
@@ -264,8 +446,7 @@
new String[] {"0.0.0.0/0", "::/0"},
mPackageName, "");
- expectUdpEcho("192.0.2.251", "192.0.2.2");
- expectUdpEcho("2001:db8:dead:beef::f00", "2001:db8:1:2::ffe");
+ checkTrafficOnVpn();
}
public void testAppDisallowed() throws Exception {
@@ -275,7 +456,6 @@
new String[] {"192.0.2.0/24", "2001:db8::/32"},
"", mPackageName);
- expectNoUdpEcho("192.0.2.251");
- expectNoUdpEcho("2001:db8:dead:beef::f00");
+ checkNoTrafficOnVpn();
}
}