Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 059e2bb3 authored by Lorenzo Colitti's avatar Lorenzo Colitti
Browse files

More APF debuggability.

1. Decode RDNSS options.
2. Keep track of how many times the program was updated.
3. Remove the leading / from the IPv4 address.

Change-Id: Ida0518a94ea7d952c82c8181b09044eff907b714
parent 7d4a7fa3
Loading
Loading
Loading
Loading
+50 −18
Original line number Original line Diff line number Diff line
@@ -252,15 +252,22 @@ public class ApfFilter {
        long mLastSeen;
        long mLastSeen;


        // For debugging only. Offsets into the packet where PIOs are.
        // For debugging only. Offsets into the packet where PIOs are.
        private final ArrayList<Integer> mPrefixOptionOffsets;
        private final ArrayList<Integer> mPrefixOptionOffsets = new ArrayList<>();

        // For debugging only. Offsets into the packet where RDNSS options are.
        private final ArrayList<Integer> mRdnssOptionOffsets = new ArrayList<>();

        // For debugging only. How many times this RA was seen.
        // For debugging only. How many times this RA was seen.
        int seenCount = 0;
        int seenCount = 0;


        // For debugging only. Returns the hex representation of the last matching packet.
        // For debugging only. Returns the hex representation of the last matching packet.
        String getLastMatchingPacket() {
        String getLastMatchingPacket() {
            return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(), false /* lowercase */);
            return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(),
                    false /* lowercase */);
        }
        }


        // For debugging only. Returns the string representation of the IPv6 address starting at
        // position pos in the packet.
        private String IPv6AddresstoString(int pos) {
        private String IPv6AddresstoString(int pos) {
            try {
            try {
                byte[] array = mPacket.array();
                byte[] array = mPacket.array();
@@ -295,19 +302,37 @@ public class ApfFilter {
            return s & 0xffffffff;
            return s & 0xffffffff;
        }
        }


        private void prefixOptionToString(StringBuffer sb, int offset) {
            String prefix = IPv6AddresstoString(offset + 16);
            int length = uint8(mPacket.get(offset + 2));
            long valid = mPacket.getInt(offset + 4);
            long preferred = mPacket.getInt(offset + 8);
            sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred));
        }

        private void rdnssOptionToString(StringBuffer sb, int offset) {
            int optLen = uint8(mPacket.get(offset + 1)) * 8;
            if (optLen < 24) return;  // Malformed or empty.
            long lifetime = uint32(mPacket.getInt(offset + 4));
            int numServers = (optLen - 8) / 16;
            sb.append("DNS ").append(lifetime).append("s");
            for (int server = 0; server < numServers; server++) {
                sb.append(" ").append(IPv6AddresstoString(offset + 8 + 16 * server));
            }
        }

        public String toString() {
        public String toString() {
            try {
            try {
                StringBuffer sb = new StringBuffer();
                StringBuffer sb = new StringBuffer();
                sb.append(String.format("RA %s -> %s %d ",
                sb.append(String.format("RA %s -> %s %ds ",
                        IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET),
                        IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET),
                        IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET),
                        IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET),
                        uint16(mPacket.getShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET))));
                        uint16(mPacket.getShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET))));
                for (int i: mPrefixOptionOffsets) {
                for (int i: mPrefixOptionOffsets) {
                    String prefix = IPv6AddresstoString(i + 16);
                    prefixOptionToString(sb, i);
                    int length = uint8(mPacket.get(i + 2));
                }
                    long valid = mPacket.getInt(i + 4);
                for (int i: mRdnssOptionOffsets) {
                    long preferred = mPacket.getInt(i + 8);
                    rdnssOptionToString(sb, i);
                    sb.append(String.format("%s/%d %d/%d ", prefix, length, valid, preferred));
                }
                }
                return sb.toString();
                return sb.toString();
            } catch (BufferUnderflowException | IndexOutOfBoundsException e) {
            } catch (BufferUnderflowException | IndexOutOfBoundsException e) {
@@ -352,8 +377,7 @@ public class ApfFilter {
                    ICMP6_RA_ROUTER_LIFETIME_OFFSET,
                    ICMP6_RA_ROUTER_LIFETIME_OFFSET,
                    ICMP6_RA_ROUTER_LIFETIME_LEN);
                    ICMP6_RA_ROUTER_LIFETIME_LEN);


            // Parse ICMPv6 options
            // Ensures that the RA is not truncated.
            mPrefixOptionOffsets = new ArrayList<>();
            mPacket.position(ICMP6_RA_OPTION_OFFSET);
            mPacket.position(ICMP6_RA_OPTION_OFFSET);
            while (mPacket.hasRemaining()) {
            while (mPacket.hasRemaining()) {
                int optionType = ((int)mPacket.get(mPacket.position())) & 0xff;
                int optionType = ((int)mPacket.get(mPacket.position())) & 0xff;
@@ -372,8 +396,10 @@ public class ApfFilter {
                        break;
                        break;
                    // These three options have the same lifetime offset and size, so process
                    // These three options have the same lifetime offset and size, so process
                    // together:
                    // together:
                    case ICMP6_ROUTE_INFO_OPTION_TYPE:
                    case ICMP6_RDNSS_OPTION_TYPE:
                    case ICMP6_RDNSS_OPTION_TYPE:
                        mRdnssOptionOffsets.add(mPacket.position());
                        // Fall through.
                    case ICMP6_ROUTE_INFO_OPTION_TYPE:
                    case ICMP6_DNSSL_OPTION_TYPE:
                    case ICMP6_DNSSL_OPTION_TYPE:
                        // Parse lifetime
                        // Parse lifetime
                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
@@ -520,6 +546,10 @@ public class ApfFilter {
    @GuardedBy("this")
    @GuardedBy("this")
    private byte[] mLastInstalledProgram;
    private byte[] mLastInstalledProgram;


    // For debugging only. How many times the program was updated since we started.
    @GuardedBy("this")
    private int mNumProgramUpdates;

    /**
    /**
     * Generate filter code to process ARP packets. Execution of this code ends in either the
     * Generate filter code to process ARP packets. Execution of this code ends in either the
     * DROP_LABEL or PASS_LABEL and does not fall off the end.
     * DROP_LABEL or PASS_LABEL and does not fall off the end.
@@ -724,6 +754,8 @@ public class ApfFilter {
        mLastTimeInstalledProgram = curTime();
        mLastTimeInstalledProgram = curTime();
        mLastInstalledProgramMinLifetime = programMinLifetime;
        mLastInstalledProgramMinLifetime = programMinLifetime;
        mLastInstalledProgram = program;
        mLastInstalledProgram = program;
        mNumProgramUpdates++;

        if (VDBG) {
        if (VDBG) {
            hexDump("Installing filter: ", program, program.length);
            hexDump("Installing filter: ", program, program.length);
        }
        }
@@ -865,19 +897,20 @@ public class ApfFilter {
    }
    }


    public synchronized void dump(IndentingPrintWriter pw) {
    public synchronized void dump(IndentingPrintWriter pw) {
        pw.println("APF caps: " + mApfCapabilities);
        pw.println("Capabilities: " + mApfCapabilities);
        pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED"));
        pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED"));
        pw.println("Multicast filtering: " + mMulticastFilter);
        pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW"));
        try {
        try {
            pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address));
            pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress());
        } catch (UnknownHostException|NullPointerException e) {}
        } catch (UnknownHostException|NullPointerException e) {}

        if (mLastTimeInstalledProgram == 0) {
        if (mLastTimeInstalledProgram == 0) {
            pw.println("No program installed.");
            pw.println("No program installed.");
            return;
            return;
        }
        }

        pw.println("Program updates: " + mNumProgramUpdates);
        pw.println(String.format(
        pw.println(String.format(
                "Last program length %d, installed %ds ago, lifetime %d",
                "Last program length %d, installed %ds ago, lifetime %ds",
                mLastInstalledProgram.length, curTime() - mLastTimeInstalledProgram,
                mLastInstalledProgram.length, curTime() - mLastTimeInstalledProgram,
                mLastInstalledProgramMinLifetime));
                mLastInstalledProgramMinLifetime));


@@ -896,6 +929,7 @@ public class ApfFilter {
            }
            }
            pw.decreaseIndent();
            pw.decreaseIndent();
        }
        }
        pw.decreaseIndent();


        if (DBG) {
        if (DBG) {
            pw.println("Last program:");
            pw.println("Last program:");
@@ -903,7 +937,5 @@ public class ApfFilter {
            pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */));
            pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */));
            pw.decreaseIndent();
            pw.decreaseIndent();
        }
        }

        pw.decreaseIndent();
    }
    }
}
}