Skip to content
Snippets Groups Projects
Commit e72b4841 authored by Ryan Zuklie's avatar Ryan Zuklie
Browse files

Add ICMP type/code and udplite/sctp in Nettrace.

This adds support for additional protocols and also provides more clear
semantics of protocol specific fields, such as only including tcpFlags
when the protocol is IPPROTO_TCP.

Test: atest libnetworkstats_test & flash and trace
Change-Id: Ic69fc75e85ebf8734027c942a253af4972ad14d8
parent 1733d3e6
No related branches found
No related tags found
No related merge requests found
......@@ -18,6 +18,7 @@
#include "netdbpf/NetworkTraceHandler.h"
#include <android-base/macros.h>
#include <arpa/inet.h>
#include <bpf/BpfUtils.h>
#include <log/log.h>
......@@ -81,14 +82,29 @@ BundleKey::BundleKey(const PacketTrace& pkt)
tag(pkt.tag),
egress(pkt.egress),
ipProto(pkt.ipProto),
ipVersion(pkt.ipVersion),
tcpFlags(pkt.tcpFlags),
localPort(ntohs(pkt.egress ? pkt.sport : pkt.dport)),
remotePort(ntohs(pkt.egress ? pkt.dport : pkt.sport)) {}
ipVersion(pkt.ipVersion) {
switch (ipProto) {
case IPPROTO_TCP:
tcpFlags = pkt.tcpFlags;
FALLTHROUGH_INTENDED;
case IPPROTO_DCCP:
case IPPROTO_UDP:
case IPPROTO_UDPLITE:
case IPPROTO_SCTP:
localPort = ntohs(pkt.egress ? pkt.sport : pkt.dport);
remotePort = ntohs(pkt.egress ? pkt.dport : pkt.sport);
break;
case IPPROTO_ICMP:
case IPPROTO_ICMPV6:
icmpType = ntohs(pkt.sport);
icmpCode = ntohs(pkt.dport);
break;
}
}
#define AGG_FIELDS(x) \
(x).ifindex, (x).uid, (x).tag, (x).egress, (x).ipProto, (x).ipVersion, \
(x).tcpFlags, (x).localPort, (x).remotePort
(x).tcpFlags, (x).localPort, (x).remotePort, (x).icmpType, (x).icmpCode
std::size_t BundleHash::operator()(const BundleKey& a) const {
std::size_t seed = 0;
......@@ -265,6 +281,8 @@ void NetworkTraceHandler::Fill(const BundleKey& src,
if (src.tcpFlags.has_value()) event->set_tcp_flags(*src.tcpFlags);
if (src.localPort.has_value()) event->set_local_port(*src.localPort);
if (src.remotePort.has_value()) event->set_remote_port(*src.remotePort);
if (src.icmpType.has_value()) event->set_icmp_type(*src.icmpType);
if (src.icmpCode.has_value()) event->set_icmp_code(*src.icmpCode);
event->set_ip_proto(src.ipProto);
......
......@@ -113,7 +113,7 @@ TEST_F(NetworkTraceHandlerTest, WriteBasicFields) {
.length = 100,
.uid = 10,
.tag = 123,
.ipProto = 6,
.ipProto = IPPROTO_TCP,
.tcpFlags = 1,
},
};
......@@ -138,12 +138,14 @@ TEST_F(NetworkTraceHandlerTest, WriteDirectionAndPorts) {
.sport = htons(8080),
.dport = htons(443),
.egress = true,
.ipProto = IPPROTO_TCP,
},
PacketTrace{
.timestampNs = 2,
.sport = htons(443),
.dport = htons(8080),
.egress = false,
.ipProto = IPPROTO_TCP,
},
};
......@@ -161,6 +163,42 @@ TEST_F(NetworkTraceHandlerTest, WriteDirectionAndPorts) {
TrafficDirection::DIR_INGRESS);
}
TEST_F(NetworkTraceHandlerTest, WriteIcmpTypeAndCode) {
std::vector<PacketTrace> input = {
PacketTrace{
.timestampNs = 1,
.sport = htons(11), // type
.dport = htons(22), // code
.egress = true,
.ipProto = IPPROTO_ICMP,
},
PacketTrace{
.timestampNs = 2,
.sport = htons(33), // type
.dport = htons(44), // code
.egress = false,
.ipProto = IPPROTO_ICMPV6,
},
};
std::vector<TracePacket> events;
ASSERT_TRUE(TraceAndSortPackets(input, &events));
ASSERT_EQ(events.size(), 2);
EXPECT_FALSE(events[0].network_packet().has_local_port());
EXPECT_FALSE(events[0].network_packet().has_remote_port());
EXPECT_THAT(events[0].network_packet().icmp_type(), 11);
EXPECT_THAT(events[0].network_packet().icmp_code(), 22);
EXPECT_THAT(events[0].network_packet().direction(),
TrafficDirection::DIR_EGRESS);
EXPECT_FALSE(events[1].network_packet().local_port());
EXPECT_FALSE(events[1].network_packet().remote_port());
EXPECT_THAT(events[1].network_packet().icmp_type(), 33);
EXPECT_THAT(events[1].network_packet().icmp_code(), 44);
EXPECT_THAT(events[1].network_packet().direction(),
TrafficDirection::DIR_INGRESS);
}
TEST_F(NetworkTraceHandlerTest, BasicBundling) {
// TODO: remove this once bundling becomes default. Until then, set arbitrary
// aggregation threshold to enable bundling.
......@@ -245,6 +283,11 @@ TEST_F(NetworkTraceHandlerTest, DropLocalPort) {
PacketTrace{.timestampNs = 4, .length = 8, .dport = b, .egress = false},
};
// Set common fields.
for (PacketTrace& pkt : input) {
pkt.ipProto = IPPROTO_TCP;
}
std::vector<TracePacket> events;
ASSERT_TRUE(TraceAndSortPackets(input, &events, config));
ASSERT_EQ(events.size(), 2);
......@@ -280,6 +323,11 @@ TEST_F(NetworkTraceHandlerTest, DropRemotePort) {
PacketTrace{.timestampNs = 4, .length = 8, .sport = b, .egress = false},
};
// Set common fields.
for (PacketTrace& pkt : input) {
pkt.ipProto = IPPROTO_TCP;
}
std::vector<TracePacket> events;
ASSERT_TRUE(TraceAndSortPackets(input, &events, config));
ASSERT_EQ(events.size(), 2);
......@@ -312,6 +360,11 @@ TEST_F(NetworkTraceHandlerTest, DropTcpFlags) {
PacketTrace{.timestampNs = 4, .length = 4, .uid = 456, .tcpFlags = 2},
};
// Set common fields.
for (PacketTrace& pkt : input) {
pkt.ipProto = IPPROTO_TCP;
}
std::vector<TracePacket> events;
ASSERT_TRUE(TraceAndSortPackets(input, &events, config));
......
......@@ -32,7 +32,7 @@ namespace bpf {
// BundleKey encodes a PacketTrace minus timestamp and length. The key should
// match many packets over time for interning. For convenience, sport/dport
// are parsed here as either local/remote port.
// are parsed here as either local/remote port or icmp type/code.
struct BundleKey {
explicit BundleKey(const PacketTrace& pkt);
......@@ -47,6 +47,8 @@ struct BundleKey {
std::optional<uint8_t> tcpFlags;
std::optional<uint16_t> localPort;
std::optional<uint16_t> remotePort;
std::optional<uint8_t> icmpType;
std::optional<uint8_t> icmpCode;
};
// BundleKeys are hashed using a simple hash combine.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment