diff options
| -rw-r--r-- | services/net/java/android/net/apf/ApfFilter.java | 32 | ||||
| -rw-r--r-- | services/tests/servicestests/src/android/net/apf/ApfTest.java | 42 |
2 files changed, 60 insertions, 14 deletions
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java index 4c7545240c23..957a8d30e2f8 100644 --- a/services/net/java/android/net/apf/ApfFilter.java +++ b/services/net/java/android/net/apf/ApfFilter.java @@ -289,8 +289,15 @@ public class ApfFilter { return System.currentTimeMillis() / DateUtils.SECOND_IN_MILLIS; } + public static class InvalidRaException extends Exception { + public InvalidRaException(String m) { + super(m); + } + } + // A class to hold information about an RA. - private class Ra { + @VisibleForTesting + class Ra { // From RFC4861: private static final int ICMP6_RA_HEADER_LEN = 16; private static final int ICMP6_RA_CHECKSUM_OFFSET = @@ -362,7 +369,7 @@ public class ApfFilter { } catch (UnsupportedOperationException e) { // array() failed. Cannot happen, mPacket is array-backed and read-write. return "???"; - } catch (ClassCastException | UnknownHostException e) { + } catch (ClassCastException|UnknownHostException e) { // Cannot happen. return "???"; } @@ -403,7 +410,7 @@ public class ApfFilter { rdnssOptionToString(sb, i); } return sb.toString(); - } catch (BufferUnderflowException | IndexOutOfBoundsException e) { + } catch (BufferUnderflowException|IndexOutOfBoundsException e) { return "<Malformed RA>"; } } @@ -436,7 +443,11 @@ public class ApfFilter { // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with // specifications. - Ra(byte[] packet, int length) { + Ra(byte[] packet, int length) throws InvalidRaException { + if (length < ICMP6_RA_OPTION_OFFSET) { + throw new InvalidRaException("Not an ICMP6 router advertisement"); + } + mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length)); mLastSeen = curTime(); @@ -445,7 +456,7 @@ public class ApfFilter { if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 || uint8(mPacket.get(IPV6_NEXT_HEADER_OFFSET)) != IPPROTO_ICMPV6 || uint8(mPacket.get(ICMP6_TYPE_OFFSET)) != ICMP6_ROUTER_ADVERTISEMENT) { - throw new IllegalArgumentException("Not an ICMP6 router advertisement"); + throw new InvalidRaException("Not an ICMP6 router advertisement"); } @@ -511,7 +522,7 @@ public class ApfFilter { break; } if (optionLength <= 0) { - throw new IllegalArgumentException(String.format( + throw new InvalidRaException(String.format( "Invalid option length opt=%d len=%d", optionType, optionLength)); } mPacket.position(position + optionLength); @@ -925,8 +936,8 @@ public class ApfFilter { // Execution will reach the end of the program if no filters match, which will pass the // packet to the AP. program = gen.generate(); - } catch (IllegalInstructionException e) { - Log.e(TAG, "Program failed to generate: ", e); + } catch (IllegalInstructionException|IllegalStateException e) { + Log.e(TAG, "Failed to generate APF program.", e); return; } mLastTimeInstalledProgram = curTime(); @@ -972,7 +983,8 @@ public class ApfFilter { * if the current APF program should be updated. * @return a ProcessRaResult enum describing what action was performed. */ - private synchronized ProcessRaResult processRa(byte[] packet, int length) { + @VisibleForTesting + synchronized ProcessRaResult processRa(byte[] packet, int length) { if (VDBG) hexDump("Read packet = ", packet, length); // Have we seen this RA before? @@ -1011,7 +1023,7 @@ public class ApfFilter { try { ra = new Ra(packet, length); } catch (Exception e) { - Log.e(TAG, "Error parsing RA: " + e); + Log.e(TAG, "Error parsing RA", e); return ProcessRaResult.PARSE_ERROR; } // Ignore 0 lifetime RAs. diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java index f7c61d15bb5f..37807b22264a 100644 --- a/services/tests/servicestests/src/android/net/apf/ApfTest.java +++ b/services/tests/servicestests/src/android/net/apf/ApfTest.java @@ -16,10 +16,6 @@ package android.net.apf; -import static android.system.OsConstants.*; - -import com.android.frameworks.servicestests.R; - import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkUtils; @@ -37,6 +33,10 @@ import android.system.ErrnoException; import android.system.Os; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; +import static android.system.OsConstants.*; + +import com.android.frameworks.servicestests.R; +import com.android.internal.util.HexDump; import org.mockito.ArgumentCaptor; import org.mockito.Mock; @@ -54,6 +54,7 @@ import java.net.InetAddress; import java.net.NetworkInterface; import java.nio.ByteBuffer; import java.util.List; +import java.util.Random; import libcore.io.IoUtils; import libcore.io.Streams; @@ -1146,6 +1147,39 @@ public class ApfTest extends AndroidTestCase { buffer.position(original); } + public void testRaParsing() throws Exception { + final int maxRandomPacketSize = 512; + final Random r = new Random(); + MockIpManagerCallback cb = new MockIpManagerCallback(); + TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST, mLog); + for (int i = 0; i < 1000; i++) { + byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)]; + r.nextBytes(packet); + try { + apfFilter.new Ra(packet, packet.length); + } catch (ApfFilter.InvalidRaException e) { + } catch (Exception e) { + throw new Exception("bad packet: " + HexDump.toHexString(packet), e); + } + } + } + + public void testRaProcessing() throws Exception { + final int maxRandomPacketSize = 512; + final Random r = new Random(); + MockIpManagerCallback cb = new MockIpManagerCallback(); + TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST, mLog); + for (int i = 0; i < 1000; i++) { + byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)]; + r.nextBytes(packet); + try { + apfFilter.processRa(packet, packet.length); + } catch (Exception e) { + throw new Exception("bad packet: " + HexDump.toHexString(packet), e); + } + } + } + /** * Call the APF interpreter the run {@code program} on {@code packet} pretending the * filter was installed {@code filter_age} seconds ago. |