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

Commit bb885a25 authored by Hungming Chen's avatar Hungming Chen
Browse files

[NFCT.NS.10] Parse CTA_TUPLE_PROTO

Test: atest TetheringCoverageTests
Change-Id: I5667cbb41e8b8d2a5cdc67f4e6c429703c1a4ed9
parent df402656
Loading
Loading
Loading
Loading
+71 −3
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import static android.net.netlink.StructNlAttr.makeNestedType;
import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
import static android.system.OsConstants.IPPROTO_TCP;
import static android.system.OsConstants.IPPROTO_UDP;

import static java.nio.ByteOrder.BIG_ENDIAN;

@@ -71,11 +73,20 @@ public class ConntrackMessage extends NetlinkMessage {
    public static class Tuple {
        public final Inet4Address srcIp;
        public final Inet4Address dstIp;
        // TODO: tuple proto for CTA_TUPLE_PROTO.

        public Tuple(TupleIpv4 ip) {
        // Both port and protocol number are unsigned numbers stored in signed integers, and that
        // callers that want to compare them to integers should either cast those integers, or
        // convert them to unsigned using Byte.toUnsignedInt() and Short.toUnsignedInt().
        public final short srcPort;
        public final short dstPort;
        public final byte protoNum;

        public Tuple(TupleIpv4 ip, TupleProto proto) {
            this.srcIp = ip.src;
            this.dstIp = ip.dst;
            this.srcPort = proto.srcPort;
            this.dstPort = proto.dstPort;
            this.protoNum = proto.protoNum;
        }
    }

@@ -94,6 +105,23 @@ public class ConntrackMessage extends NetlinkMessage {
        }
    }

    /**
     * A tuple for the conntrack connection protocol.
     *
     * see also CTA_TUPLE_PROTO.
     */
    public static class TupleProto {
        public final byte protoNum;
        public final short srcPort;
        public final short dstPort;

        public TupleProto(byte protoNum, short srcPort, short dstPort) {
            this.protoNum = protoNum;
            this.srcPort = srcPort;
            this.dstPort = dstPort;
        }
    }

    public static byte[] newIPv4TimeoutUpdateRequest(
            int proto, Inet4Address src, int sport, Inet4Address dst, int dport, int timeoutSec) {
        // *** STYLE WARNING ***
@@ -226,6 +254,7 @@ public class ConntrackMessage extends NetlinkMessage {
        if (byteBuffer == null) return null;

        TupleIpv4 tupleIpv4 = null;
        TupleProto tupleProto = null;

        final int baseOffset = byteBuffer.position();
        StructNlAttr nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_IP), byteBuffer);
@@ -234,7 +263,14 @@ public class ConntrackMessage extends NetlinkMessage {
        }
        if (tupleIpv4 == null) return null;

        return new Tuple(tupleIpv4);
        byteBuffer.position(baseOffset);
        nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_PROTO), byteBuffer);
        if (nlAttr != null) {
            tupleProto = parseTupleProto(nlAttr.getValueAsByteBuffer());
        }
        if (tupleProto == null) return null;

        return new Tuple(tupleIpv4, tupleProto);
    }

    @Nullable
@@ -267,6 +303,38 @@ public class ConntrackMessage extends NetlinkMessage {
        return new TupleIpv4(src, dst);
    }

    @Nullable
    private static TupleProto parseTupleProto(@Nullable ByteBuffer byteBuffer) {
        if (byteBuffer == null) return null;

        byte protoNum = 0;
        short srcPort = 0;
        short dstPort = 0;

        final int baseOffset = byteBuffer.position();
        StructNlAttr nlAttr = findNextAttrOfType(CTA_PROTO_NUM, byteBuffer);
        if (nlAttr != null) {
            protoNum = nlAttr.getValueAsByte((byte) 0);
        }
        if (!(protoNum == IPPROTO_TCP || protoNum == IPPROTO_UDP)) return null;

        byteBuffer.position(baseOffset);
        nlAttr = StructNlAttr.findNextAttrOfType(CTA_PROTO_SRC_PORT, byteBuffer);
        if (nlAttr != null) {
            srcPort = nlAttr.getValueAsBe16((short) 0);
        }
        if (srcPort == 0) return null;

        byteBuffer.position(baseOffset);
        nlAttr = StructNlAttr.findNextAttrOfType(CTA_PROTO_DST_PORT, byteBuffer);
        if (nlAttr != null) {
            dstPort = nlAttr.getValueAsBe16((short) 0);
        }
        if (dstPort == 0) return null;

        return new TupleProto(protoNum, srcPort, dstPort);
    }

    /**
     * Netfilter header.
     */
+28 −0
Original line number Diff line number Diff line
@@ -183,6 +183,23 @@ public class StructNlAttr {
        return NetlinkConstants.alignedLengthOf(nla_len);
    }

    /**
     * Get attribute value as BE16.
     */
    public short getValueAsBe16(short defaultValue) {
        final ByteBuffer byteBuffer = getValueAsByteBuffer();
        if (byteBuffer == null || byteBuffer.remaining() != Short.BYTES) {
            return defaultValue;
        }
        final ByteOrder originalOrder = byteBuffer.order();
        try {
            byteBuffer.order(ByteOrder.BIG_ENDIAN);
            return byteBuffer.getShort();
        } finally {
            byteBuffer.order(originalOrder);
        }
    }

    public int getValueAsBe32(int defaultValue) {
        final ByteBuffer byteBuffer = getValueAsByteBuffer();
        if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) {
@@ -207,6 +224,17 @@ public class StructNlAttr {
        return byteBuffer;
    }

    /**
     * Get attribute value as byte.
     */
    public byte getValueAsByte(byte defaultValue) {
        final ByteBuffer byteBuffer = getValueAsByteBuffer();
        if (byteBuffer == null || byteBuffer.remaining() != Byte.BYTES) {
            return defaultValue;
        }
        return getValueAsByteBuffer().get();
    }

    public int getValueAsInt(int defaultValue) {
        final ByteBuffer byteBuffer = getValueAsByteBuffer();
        if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) {
+46 −7
Original line number Diff line number Diff line
@@ -129,25 +129,64 @@ public class ConntrackMonitorTest {
    }

    // TODO: Add conntrack message attributes to have further verification.
    public static final String CT_V4NEW_HEX =
    public static final String CT_V4NEW_TCP_HEX =
            // CHECKSTYLE:OFF IndentationCheck
            // struct nlmsghdr
            "14000000" +      // length = 20
            "8C000000" +      // length = 140
            "0001" +          // type = NFNL_SUBSYS_CTNETLINK (1) << 8 | IPCTNL_MSG_CT_NEW (0)
            "0006" +          // flags = NLM_F_CREATE | NLM_F_EXCL
            "0006" +          // flags = NLM_F_CREATE (1 << 10) | NLM_F_EXCL (1 << 9)
            "00000000" +      // seqno = 0
            "00000000" +      // pid = 0
            // struct nfgenmsg
            "02" +            // nfgen_family = AF_INET
            "00" +            // version = NFNETLINK_V0
            "0000";           // res_id
            "1234" +          // res_id = 0x1234 (big endian)
             // struct nlattr
            "3400" +          // nla_len = 52
            "0180" +          // nla_type = nested CTA_TUPLE_ORIG
                // struct nlattr
                "1400" +      // nla_len = 20
                "0180" +      // nla_type = nested CTA_TUPLE_IP
                    "0800 0100 C0A8500C" +  // nla_type=CTA_IP_V4_SRC, ip=192.168.80.12
                    "0800 0200 8C700874" +  // nla_type=CTA_IP_V4_DST, ip=140.112.8.116
                // struct nlattr
                "1C00" +      // nla_len = 28
                "0280" +      // nla_type = nested CTA_TUPLE_PROTO
                    "0500 0100 06 000000" +  // nla_type=CTA_PROTO_NUM, proto=IPPROTO_TCP (6)
                    "0600 0200 F3F1 0000" +  // nla_type=CTA_PROTO_SRC_PORT, port=62449 (big endian)
                    "0600 0300 01BB 0000" +  // nla_type=CTA_PROTO_DST_PORT, port=443 (big endian)
            // struct nlattr
            "3400" +          // nla_len = 52
            "0280" +          // nla_type = nested CTA_TUPLE_REPLY
                // struct nlattr
                "1400" +      // nla_len = 20
                "0180" +      // nla_type = nested CTA_TUPLE_IP
                    "0800 0100 8C700874" +  // nla_type=CTA_IP_V4_SRC, ip=140.112.8.116
                    "0800 0200 6451B301" +  // nla_type=CTA_IP_V4_DST, ip=100.81.179.1
                // struct nlattr
                "1C00" +      // nla_len = 28
                "0280" +      // nla_type = nested CTA_TUPLE_PROTO
                    "0500 0100 06 000000" +  // nla_type=CTA_PROTO_NUM, proto=IPPROTO_TCP (6)
                    "0600 0200 01BB 0000" +  // nla_type=CTA_PROTO_SRC_PORT, port=443 (big endian)
                    "0600 0300 F3F1 0000" +  // nla_type=CTA_PROTO_DST_PORT, port=62449 (big endian)
            // struct nlattr
            "0800" +          // nla_len = 8
            "0300" +          // nla_type = CTA_STATUS
            "0000019e" +      // nla_value = 0b110011110 (big endian)
                              // IPS_SEEN_REPLY (1 << 1) | IPS_ASSURED (1 << 2) |
                              // IPS_CONFIRMED (1 << 3) | IPS_SRC_NAT (1 << 4) |
                              // IPS_SRC_NAT_DONE (1 << 7) | IPS_DST_NAT_DONE (1 << 8)
            // struct nlattr
            "0800" +          // nla_len = 8
            "0700" +          // nla_type = CTA_TIMEOUT
            "00000078";       // nla_value = 120 (big endian)
            // CHECKSTYLE:ON IndentationCheck
    public static final byte[] CT_V4NEW_BYTES =
            HexEncoding.decode(CT_V4NEW_HEX.replaceAll(" ", "").toCharArray(), false);
    public static final byte[] CT_V4NEW_TCP_BYTES =
            HexEncoding.decode(CT_V4NEW_TCP_HEX.replaceAll(" ", "").toCharArray(), false);

    @Test
    public void testConntrackEvent_New() throws Exception {
        mConntrackMonitor.sendMessage(CT_V4NEW_BYTES);
        mConntrackMonitor.sendMessage(CT_V4NEW_TCP_BYTES);
        verify(mConsumer, timeout(TIMEOUT_MS)).accept(any() /* TODO: check the content */);
    }
}
+19 −5
Original line number Diff line number Diff line
@@ -172,6 +172,9 @@ public class ConntrackMessageTest {
                conntrackMessage.tupleOrig.srcIp);
        assertEquals(InetAddress.parseNumericAddress("23.211.13.26"),
                conntrackMessage.tupleOrig.dstIp);
        assertEquals((byte) OsConstants.IPPROTO_TCP, conntrackMessage.tupleOrig.protoNum);
        assertEquals((short) 44333, conntrackMessage.tupleOrig.srcPort);
        assertEquals((short) 443, conntrackMessage.tupleOrig.dstPort);

        assertNull(conntrackMessage.tupleReply);

@@ -218,6 +221,9 @@ public class ConntrackMessageTest {
                conntrackMessage.tupleOrig.srcIp);
        assertEquals(InetAddress.parseNumericAddress("216.58.197.10"),
                conntrackMessage.tupleOrig.dstIp);
        assertEquals((byte) OsConstants.IPPROTO_UDP, conntrackMessage.tupleOrig.protoNum);
        assertEquals((short) 37069, conntrackMessage.tupleOrig.srcPort);
        assertEquals((short) 443, conntrackMessage.tupleOrig.dstPort);

        assertNull(conntrackMessage.tupleReply);

@@ -225,7 +231,6 @@ public class ConntrackMessageTest {
        assertEquals(180, conntrackMessage.timeoutSec);
    }

    // TODO: Add conntrack message attributes to have further verification.
    public static final String CT_V4NEW_TCP_HEX =
            // CHECKSTYLE:OFF IndentationCheck
            // struct nlmsghdr
@@ -310,16 +315,20 @@ public class ConntrackMessageTest {
                conntrackMessage.tupleOrig.srcIp);
        assertEquals(InetAddress.parseNumericAddress("140.112.8.116"),
                conntrackMessage.tupleOrig.dstIp);
        assertEquals((byte) OsConstants.IPPROTO_TCP, conntrackMessage.tupleOrig.protoNum);
        assertEquals((short) 62449, conntrackMessage.tupleOrig.srcPort);
        assertEquals((short) 443, conntrackMessage.tupleOrig.dstPort);

        assertEquals(InetAddress.parseNumericAddress("140.112.8.116"),
                conntrackMessage.tupleReply.srcIp);
        assertEquals(InetAddress.parseNumericAddress("100.81.179.1"),
                conntrackMessage.tupleReply.dstIp);
        assertEquals((byte) OsConstants.IPPROTO_TCP, conntrackMessage.tupleReply.protoNum);
        assertEquals((short) 443, conntrackMessage.tupleReply.srcPort);
        assertEquals((short) 62449, conntrackMessage.tupleReply.dstPort);

        assertEquals(0x198, conntrackMessage.status);
        assertEquals(120, conntrackMessage.timeoutSec);

        // TODO: parse the attribute CTA_TUPLE_PROTO once ConntrackMessage supports.
    }

    @Test
@@ -367,7 +376,12 @@ public class ConntrackMessageTest {
            // nested CTA_TUPLE_IP has no nla_value.
            + "1C000000 0001 0006 00000000 00000000 02 00 0000 0800 0180 0400 0180"
            // nested CTA_IP_V4_SRC has no nla_value.
            + "20000000 0001 0006 00000000 00000000 02 00 0000 0C00 0180 0800 0180 0400 0100";
            + "20000000 0001 0006 00000000 00000000 02 00 0000 0C00 0180 0800 0180 0400 0100"
            // nested CTA_TUPLE_PROTO has no nla_value.
            // <--           nlmsghr           -->|<-nfgenmsg->|<--    CTA_TUPLE_ORIG
            + "30000000 0001 0006 00000000 00000000 02 00 0000 1C00 0180 1400 0180 0800 0100"
            //                                  -->|
            + "C0A8500C 0800 0200 8C700874 0400 0280";
            // CHECKSTYLE:ON IndentationCheck
    public static final byte[] CT_MALFORMED_BYTES =
            HexEncoding.decode(CT_MALFORMED_HEX.replaceAll(" ", "").toCharArray(), false);
@@ -386,6 +400,6 @@ public class ConntrackMessageTest {
                    OsConstants.NETLINK_NETFILTER);
            messageCount++;
        }
        assertEquals(3, messageCount);
        assertEquals(4, messageCount);
    }
}