Merge "Export AIDL files as a filegroup for framework.jar"
diff --git a/libnetdutils/Netfilter.cpp b/libnetdutils/Netfilter.cpp
index 6e36f34..bb43de0 100644
--- a/libnetdutils/Netfilter.cpp
+++ b/libnetdutils/Netfilter.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <endian.h>
+#include <arpa/inet.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netlink.h>
@@ -25,6 +25,6 @@
std::ostream& operator<<(std::ostream& os, const nfgenmsg& msg) {
return os << std::hex << "nfgenmsg["
<< "family: 0x" << static_cast<int>(msg.nfgen_family) << ", version: 0x"
- << static_cast<int>(msg.version) << ", res_id: 0x" << be16toh(msg.res_id) << "]"
+ << static_cast<int>(msg.version) << ", res_id: 0x" << ntohs(msg.res_id) << "]"
<< std::dec;
}
diff --git a/server/Android.mk b/server/Android.mk
index 51d2918..d91d063 100644
--- a/server/Android.mk
+++ b/server/Android.mk
@@ -87,6 +87,7 @@
libnetdaidl \
libnetutils \
libnetdutils \
+ libselinux \
libssl \
libsysutils \
libbase \
diff --git a/server/Controllers.cpp b/server/Controllers.cpp
index 4231a53..8b02f60 100644
--- a/server/Controllers.cpp
+++ b/server/Controllers.cpp
@@ -188,13 +188,18 @@
Controllers::Controllers()
: clatdCtrl(&netCtrl),
wakeupCtrl(
- [this](const std::string& prefix, uid_t uid, gid_t gid, uint64_t timestampNs) {
+ [this](const WakeupController::ReportArgs& args) {
const auto listener = eventReporter.getNetdEventListener();
if (listener == nullptr) {
ALOGE("getNetdEventListener() returned nullptr. dropping wakeup event");
return;
}
- listener->onWakeupEvent(String16(prefix.c_str()), uid, gid, timestampNs);
+ String16 prefix = String16(args.prefix.c_str());
+ String16 srcIp = String16(args.srcIp.c_str());
+ String16 dstIp = String16(args.dstIp.c_str());
+ listener->onWakeupEvent(prefix, args.uid, args.ethertype, args.ipNextHeader,
+ args.dstHw, srcIp, dstIp, args.srcPort, args.dstPort,
+ args.timestampNs);
},
&iptablesRestoreCtrl) {
InterfaceController::initializeAll();
diff --git a/server/FwmarkServer.cpp b/server/FwmarkServer.cpp
index 5fe4cbe..32b856a 100644
--- a/server/FwmarkServer.cpp
+++ b/server/FwmarkServer.cpp
@@ -24,6 +24,7 @@
#include "resolv_netid.h"
#include <netinet/in.h>
+#include <selinux/selinux.h>
#include <sys/socket.h>
#include <unistd.h>
#include <utils/String16.h>
@@ -36,10 +37,33 @@
namespace android {
namespace net {
-const char UPDATE_DEVICE_STATS[] = "android.permission.UPDATE_DEVICE_STATS";
+constexpr const char *UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
+constexpr const char *SYSTEM_SERVER_CONTEXT = "u:r:system_server:s0";
+
+bool isSystemServer(SocketClient* client) {
+ if (client->getUid() != AID_SYSTEM) {
+ return false;
+ }
+
+ char *context;
+ if (getpeercon(client->getSocket(), &context)) {
+ return false;
+ }
+
+ // We can't use context_new and context_type_get as they're private to libselinux. So just do
+ // a string match instead.
+ bool ret = !strcmp(context, SYSTEM_SERVER_CONTEXT);
+ freecon(context);
+
+ return ret;
+}
bool hasUpdateDeviceStatsPermission(SocketClient* client) {
- return checkPermission(String16(UPDATE_DEVICE_STATS), client->getPid(), client->getUid());
+ // If the caller is the system server, allow without any further checks.
+ // Otherwise, if the system server's binder thread pool is full, and all the threads are
+ // blocked on a thread that's waiting for us to complete, we deadlock. http://b/69389492
+ return isSystemServer(client) ||
+ checkPermission(String16(UPDATE_DEVICE_STATS), client->getPid(), client->getUid());
}
FwmarkServer::FwmarkServer(NetworkController* networkController, EventReporter* eventReporter,
diff --git a/server/NFLogListener.cpp b/server/NFLogListener.cpp
index 874cb16..7e3242f 100644
--- a/server/NFLogListener.cpp
+++ b/server/NFLogListener.cpp
@@ -19,7 +19,7 @@
#include <sstream>
#include <vector>
-#include <endian.h>
+#include <arpa/inet.h>
#include <linux/netfilter/nfnetlink_log.h>
#include <cutils/log.h>
@@ -46,8 +46,7 @@
constexpr int kNFLogConfigMsgType = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
constexpr int kNFLogPacketMsgType = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_PACKET;
constexpr int kNetlinkDoneMsgType = (NFNL_SUBSYS_NONE << 8) | NLMSG_DONE;
-constexpr size_t kPacketRange = 0;
-constexpr size_t kCopyMode = NFULNL_COPY_NONE;
+constexpr size_t kDefaultPacketRange = 0;
namespace {
@@ -94,11 +93,11 @@
msg.nlhdr.nlmsg_type = kNFLogConfigMsgType;
msg.nlhdr.nlmsg_flags = NLM_F_REQUEST;
msg.nfhdr.nfgen_family = AF_UNSPEC;
- msg.nfhdr.res_id = htobe16(nfLogGroup);
+ msg.nfhdr.res_id = htons(nfLogGroup);
msg.attr.nfa_len = sizeof(msg.attr) + sizeof(msg.mode);
msg.attr.nfa_type = NFULA_CFG_MODE;
msg.mode.copy_mode = mode;
- msg.mode.copy_range = htobe32(range);
+ msg.mode.copy_range = htonl(range);
return send(makeSlice(msg));
}
@@ -115,7 +114,7 @@
msg.nlhdr.nlmsg_type = kNFLogConfigMsgType;
msg.nlhdr.nlmsg_flags = NLM_F_REQUEST;
msg.nfhdr.nfgen_family = AF_UNSPEC;
- msg.nfhdr.res_id = htobe16(nfLogGroup);
+ msg.nfhdr.res_id = htons(nfLogGroup);
msg.attr.nfa_len = sizeof(msg.attr) + sizeof(msg.cmd);
msg.attr.nfa_type = NFULA_CFG_CMD;
msg.cmd.command = NFULNL_CFG_CMD_BIND;
@@ -135,7 +134,7 @@
msg.nlhdr.nlmsg_type = kNFLogConfigMsgType;
msg.nlhdr.nlmsg_flags = NLM_F_REQUEST;
msg.nfhdr.nfgen_family = AF_UNSPEC;
- msg.nfhdr.res_id = htobe16(nfLogGroup);
+ msg.nfhdr.res_id = htons(nfLogGroup);
msg.attr.nfa_len = sizeof(msg.attr) + sizeof(msg.cmd);
msg.attr.nfa_type = NFULA_CFG_CMD;
msg.cmd.command = NFULNL_CFG_CMD_UNBIND;
@@ -151,7 +150,7 @@
nfgenmsg nfmsg = {};
extract(msg, nfmsg);
std::lock_guard<std::mutex> guard(mMutex);
- const auto& fn = findWithDefault(mDispatchMap, be16toh(nfmsg.res_id), kDefaultDispatchFn);
+ const auto& fn = findWithDefault(mDispatchMap, ntohs(nfmsg.res_id), kDefaultDispatchFn);
fn(nlmsg, nfmsg, drop(msg, sizeof(nfmsg)));
};
expectOk(mListener->subscribe(kNFLogPacketMsgType, rxHandler));
@@ -176,6 +175,11 @@
}
Status NFLogListener::subscribe(uint16_t nfLogGroup, const DispatchFn& fn) {
+ return subscribe(nfLogGroup, kDefaultPacketRange, fn);
+}
+
+Status NFLogListener::subscribe(
+ uint16_t nfLogGroup, uint32_t copyRange, const DispatchFn& fn) {
const auto sendFn = [this](const Slice msg) { return mListener->send(msg); };
// Install fn into the dispatch map BEFORE requesting delivery of messages
{
@@ -185,7 +189,8 @@
RETURN_IF_NOT_OK(cfgCmdBind(sendFn, nfLogGroup));
// Mode must be set for every nfLogGroup
- return cfgMode(sendFn, nfLogGroup, kPacketRange, kCopyMode);
+ const uint8_t copyMode = copyRange > 0 ? NFULNL_COPY_PACKET : NFULNL_COPY_NONE;
+ return cfgMode(sendFn, nfLogGroup, copyRange, copyMode);
}
Status NFLogListener::unsubscribe(uint16_t nfLogGroup) {
diff --git a/server/NFLogListener.h b/server/NFLogListener.h
index 9e5b8a4..7eb9d10 100644
--- a/server/NFLogListener.h
+++ b/server/NFLogListener.h
@@ -40,6 +40,11 @@
// subscribe() and join() must not be called from the stack of fn().
virtual netdutils::Status subscribe(uint16_t nfLogGroup, const DispatchFn& fn) = 0;
+ // Overloaded version of subscribe which allows to specify a copyRange for obtaining packet
+ // payloads.
+ virtual netdutils::Status subscribe(
+ uint16_t nfLogGroup, uint32_t copyRange, const DispatchFn& fn) = 0;
+
// Halt delivery of messages from a nfLogGroup previously subscribed to above.
//
// Threadsafe.
@@ -64,6 +69,9 @@
netdutils::Status subscribe(uint16_t nfLogGroup, const DispatchFn& fn) override;
+ netdutils::Status subscribe(
+ uint16_t nfLogGroup, uint32_t copyRange, const DispatchFn& fn) override;
+
netdutils::Status unsubscribe(uint16_t nfLogGroup) override;
private:
diff --git a/server/NFLogListenerTest.cpp b/server/NFLogListenerTest.cpp
index d397b2a..c7ee439 100644
--- a/server/NFLogListenerTest.cpp
+++ b/server/NFLogListenerTest.cpp
@@ -19,7 +19,7 @@
#include <iostream>
#include <mutex>
-#include <endian.h>
+#include <arpa/inet.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <linux/netfilter/nfnetlink_log.h>
@@ -92,7 +92,7 @@
msg.nlmsg.nlmsg_type = kNFLogPacketMsgType;
msg.nlmsg.nlmsg_len = sizeof(msg);
- msg.nfmsg.res_id = htobe16(type);
+ msg.nfmsg.res_id = htons(type);
mPacketFn(msg.nlmsg, drop(makeSlice(msg), sizeof(msg.nlmsg)));
}
@@ -121,7 +121,7 @@
constexpr uint16_t kType = 38;
const auto dispatchFn = [&invocations, kType](const nlmsghdr&, const nfgenmsg& nfmsg,
const netdutils::Slice) {
- EXPECT_EQ(kType, be16toh(nfmsg.res_id));
+ EXPECT_EQ(kType, ntohs(nfmsg.res_id));
++invocations;
};
subscribe(kType, dispatchFn);
diff --git a/server/NetlinkCommands.h b/server/NetlinkCommands.h
index 7c0d4a8..ef1ff48 100644
--- a/server/NetlinkCommands.h
+++ b/server/NetlinkCommands.h
@@ -29,7 +29,13 @@
const sockaddr_nl KERNEL_NLADDR = {AF_NETLINK, 0, 0, 0};
const uint16_t NETLINK_REQUEST_FLAGS = NLM_F_REQUEST | NLM_F_ACK;
-const uint16_t NETLINK_CREATE_REQUEST_FLAGS = NETLINK_REQUEST_FLAGS | NLM_F_CREATE | NLM_F_EXCL;
+const uint16_t NETLINK_ROUTE_CREATE_FLAGS = NETLINK_REQUEST_FLAGS | NLM_F_CREATE | NLM_F_EXCL;
+// Don't create rules with NLM_F_EXCL, because operations such as changing network permissions rely
+// on make-before-break. The kernel did not complain about duplicate rules until ~4.9, at which
+// point it started returning EEXIST. See for example b/69607866 . We can't just ignore the EEXIST
+// because if we hit it, the rule was not created, but we will think it was, and we'll then trip up
+// trying to delete it.
+const uint16_t NETLINK_RULE_CREATE_FLAGS = NETLINK_REQUEST_FLAGS | NLM_F_CREATE;
const uint16_t NETLINK_DUMP_FLAGS = NLM_F_REQUEST | NLM_F_DUMP;
// Generic code for processing netlink dumps.
diff --git a/server/RouteController.cpp b/server/RouteController.cpp
index 2799075..198c8a8 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -283,7 +283,7 @@
{ PADDING_BUFFER, oifPadding },
};
- uint16_t flags = (action == RTM_NEWRULE) ? NETLINK_CREATE_REQUEST_FLAGS : NETLINK_REQUEST_FLAGS;
+ uint16_t flags = (action == RTM_NEWRULE) ? NETLINK_RULE_CREATE_FLAGS : NETLINK_REQUEST_FLAGS;
for (size_t i = 0; i < ARRAY_SIZE(AF_FAMILIES); ++i) {
rule.family = AF_FAMILIES[i];
if (int ret = sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov), nullptr)) {
@@ -400,8 +400,7 @@
{ &PRIO_THROW, isDefaultThrowRoute ? sizeof(PRIO_THROW) : 0 },
};
- uint16_t flags = (action == RTM_NEWROUTE) ? NETLINK_CREATE_REQUEST_FLAGS :
- NETLINK_REQUEST_FLAGS;
+ uint16_t flags = (action == RTM_NEWROUTE) ? NETLINK_ROUTE_CREATE_FLAGS : NETLINK_REQUEST_FLAGS;
int ret = sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov), nullptr);
if (ret) {
ALOGE("Error %s route %s -> %s %s to table %u: %s",
diff --git a/server/WakeupController.cpp b/server/WakeupController.cpp
index 9e1e43b..07ab87a 100644
--- a/server/WakeupController.cpp
+++ b/server/WakeupController.cpp
@@ -16,11 +16,19 @@
#define LOG_TAG "WakeupController"
-#include <endian.h>
+#include <arpa/inet.h>
+#include <iostream>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_log.h>
-#include <iostream>
+#include <sys/socket.h>
+#include <netinet/if_ether.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <android-base/strings.h>
#include <android-base/stringprintf.h>
#include <cutils/log.h>
#include <netdutils/Netfilter.h>
@@ -39,6 +47,72 @@
const char WakeupController::LOCAL_MANGLE_INPUT[] = "wakeupctrl_mangle_INPUT";
+const uint32_t WakeupController::kDefaultPacketCopyRange =
+ sizeof(struct tcphdr) + sizeof(struct ip6_hdr);
+
+static void extractIpPorts(WakeupController::ReportArgs& args, Slice payload) {
+ switch (args.ipNextHeader) {
+ case IPPROTO_TCP: {
+ struct tcphdr header;
+ if (extract(payload, header) < sizeof(struct tcphdr)) {
+ return;
+ }
+ args.srcPort = ntohs(header.th_sport);
+ args.dstPort = ntohs(header.th_dport);
+ break;
+ }
+ case IPPROTO_UDP: {
+ struct udphdr header;
+ if (extract(payload, header) < sizeof(struct udphdr)) {
+ return;
+ }
+ args.srcPort = ntohs(header.uh_sport);
+ args.dstPort = ntohs(header.uh_dport);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void extractIpHeader(WakeupController::ReportArgs& args, Slice payload) {
+ switch (args.ethertype) {
+ case ETH_P_IP: {
+ struct iphdr header;
+ if (extract(payload, header) < sizeof(struct iphdr)) {
+ return;
+ }
+ args.ipNextHeader = header.protocol;
+ char addr[INET_ADDRSTRLEN] = {};
+ inet_ntop(AF_INET, &header.saddr, addr, sizeof(addr));
+ args.srcIp = addr;
+ inet_ntop(AF_INET, &header.daddr, addr, sizeof(addr));
+ args.dstIp = addr;
+ extractIpPorts(args, drop(payload, header.ihl * 4)); // ipv4 IHL counts 32 bit words.
+ break;
+ }
+ case ETH_P_IPV6: {
+ struct ip6_hdr header;
+ if (extract(payload, header) < sizeof(struct ip6_hdr)) {
+ return;
+ }
+ args.ipNextHeader = header.ip6_nxt;
+ char addr[INET6_ADDRSTRLEN] = {};
+ inet_ntop(AF_INET6, &header.ip6_src, addr, sizeof(addr));
+ args.srcIp = addr;
+ inet_ntop(AF_INET6, &header.ip6_dst, addr, sizeof(addr));
+ args.dstIp = addr;
+ // TODO: also deal with extension headers
+ if (args.ipNextHeader == IPPROTO_TCP || args.ipNextHeader == IPPROTO_UDP) {
+ extractIpPorts(args, drop(payload, sizeof(header)));
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
WakeupController::~WakeupController() {
expectOk(mListener->unsubscribe(NetlinkManager::NFLOG_WAKEUP_GROUP));
}
@@ -46,40 +120,75 @@
netdutils::Status WakeupController::init(NFLogListenerInterface* listener) {
mListener = listener;
const auto msgHandler = [this](const nlmsghdr&, const nfgenmsg&, const Slice msg) {
- std::string prefix;
- uid_t uid = -1;
- gid_t gid = -1;
- uint64_t timestampNs = -1;
- const auto attrHandler = [&prefix, &uid, &gid, ×tampNs](const nlattr attr,
- const Slice payload) {
+
+ struct WakeupController::ReportArgs args = {
+ .uid = -1,
+ .gid = -1,
+ .ethertype = -1,
+ .ipNextHeader = -1,
+ .srcPort = -1,
+ .dstPort = -1,
+ // and all other fields set to 0 as the default
+ };
+ bool parseAgain = false;
+
+ const auto attrHandler = [&args, &parseAgain](const nlattr attr, const Slice payload) {
switch (attr.nla_type) {
case NFULA_TIMESTAMP: {
timespec ts = {};
extract(payload, ts);
constexpr uint64_t kNsPerS = 1000000000ULL;
- timestampNs = be32toh(ts.tv_nsec) + (be32toh(ts.tv_sec) * kNsPerS);
+ args.timestampNs = ntohl(ts.tv_nsec) + (ntohl(ts.tv_sec) * kNsPerS);
break;
}
case NFULA_PREFIX:
// Strip trailing '\0'
- prefix = toString(take(payload, payload.size() - 1));
+ args.prefix = toString(take(payload, payload.size() - 1));
break;
case NFULA_UID:
- extract(payload, uid);
- uid = be32toh(uid);
+ extract(payload, args.uid);
+ args.uid = ntohl(args.uid);
break;
case NFULA_GID:
- extract(payload, gid);
- gid = be32toh(gid);
+ extract(payload, args.gid);
+ args.gid = ntohl(args.gid);
+ break;
+ case NFULA_HWADDR: {
+ struct nfulnl_msg_packet_hw hwaddr = {};
+ extract(payload, hwaddr);
+ size_t hwAddrLen = ntohs(hwaddr.hw_addrlen);
+ hwAddrLen = std::min(hwAddrLen, sizeof(hwaddr.hw_addr));
+ args.dstHw.assign(hwaddr.hw_addr, hwaddr.hw_addr + hwAddrLen);
+ break;
+ }
+ case NFULA_PACKET_HDR: {
+ struct nfulnl_msg_packet_hdr packetHdr = {};
+ extract(payload, packetHdr);
+ args.ethertype = ntohs(packetHdr.hw_protocol);
+ break;
+ }
+ case NFULA_PAYLOAD:
+ // The packet payload is expected to come last in the Netlink message.
+ // At that point NFULA_PACKET_HDR has already been parsed and processed.
+ // If this is not the case, set parseAgain to true.
+ parseAgain = (args.ethertype == -1);
+ extractIpHeader(args, payload);
break;
default:
break;
}
};
+
forEachNetlinkAttribute(msg, attrHandler);
- mReport(prefix, uid, gid, timestampNs);
+ if (parseAgain) {
+ // NFULA_PAYLOAD was parsed before NFULA_PACKET_HDR.
+ // Now that the ethertype is known, reparse msg for correctly extracting the payload.
+ forEachNetlinkAttribute(msg, attrHandler);
+ }
+ mReport(args);
};
- return mListener->subscribe(NetlinkManager::NFLOG_WAKEUP_GROUP, msgHandler);
+ return mListener->subscribe(NetlinkManager::NFLOG_WAKEUP_GROUP,
+ WakeupController::kDefaultPacketCopyRange, msgHandler);
}
Status WakeupController::addInterface(const std::string& ifName, const std::string& prefix,
@@ -100,10 +209,11 @@
constexpr int kRateLimit = 10;
const char kFormat[] =
"*mangle\n%s %s -i %s -j NFLOG --nflog-prefix %s --nflog-group %d --nflog-threshold %d"
- " -m mark --mark 0x%08x/0x%08x -m limit --limit %d/s\nCOMMIT\n";
+ " --nflog-range %d -m mark --mark 0x%08x/0x%08x -m limit --limit %d/s\nCOMMIT\n";
const auto cmd = StringPrintf(
- kFormat, action.c_str(), WakeupController::LOCAL_MANGLE_INPUT, ifName.c_str(),
- prefix.c_str(), NetlinkManager::NFLOG_WAKEUP_GROUP, kBatch, mark, mask, kRateLimit);
+ kFormat, action.c_str(), WakeupController::LOCAL_MANGLE_INPUT, ifName.c_str(),
+ prefix.c_str(), NetlinkManager::NFLOG_WAKEUP_GROUP, kBatch,
+ WakeupController::kDefaultPacketCopyRange, mark, mask, kRateLimit);
std::string out;
auto rv = mIptables->execute(V4V6, cmd, &out);
diff --git a/server/WakeupController.h b/server/WakeupController.h
index e147f3e..841051b 100644
--- a/server/WakeupController.h
+++ b/server/WakeupController.h
@@ -29,11 +29,30 @@
class WakeupController {
public:
- using ReportFn = std::function<void(const std::string&, uid_t, gid_t, uint64_t)>;
+
+ // Simple data struct for passing back packet wakeup event information to the ReportFn callback.
+ struct ReportArgs {
+ std::string prefix;
+ uint64_t timestampNs;
+ int uid;
+ int gid;
+ int ethertype;
+ int ipNextHeader;
+ std::vector<uint8_t> dstHw;
+ std::string srcIp;
+ std::string dstIp;
+ int srcPort;
+ int dstPort;
+ };
+
+ // Callback that is triggered for every wakeup event.
+ using ReportFn = std::function<void(const struct ReportArgs&)>;
// iptables chain where wakeup packets are matched
static const char LOCAL_MANGLE_INPUT[];
+ static const uint32_t kDefaultPacketCopyRange;
+
WakeupController(ReportFn report, IptablesRestoreInterface* iptables)
: mReport(report), mIptables(iptables) {}
diff --git a/server/WakeupControllerTest.cpp b/server/WakeupControllerTest.cpp
index 05e899c..f7812e5 100644
--- a/server/WakeupControllerTest.cpp
+++ b/server/WakeupControllerTest.cpp
@@ -16,6 +16,12 @@
#include <linux/netfilter/nfnetlink_log.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -32,12 +38,16 @@
namespace android {
namespace net {
+const uint32_t kDefaultPacketCopyRange = WakeupController::kDefaultPacketCopyRange;
+
using netdutils::status::ok;
class MockNetdEventListener {
public:
- MOCK_METHOD4(onWakeupEvent,
- void(const std::string& prefix, uid_t uid, gid_t gid, uint64_t timestampNs));
+ MOCK_METHOD10(onWakeupEvent, void(
+ const std::string& prefix, int uid, int ether, int ipNextHeader,
+ std::vector<uint8_t> dstHw, const std::string& srcIp, const std::string& dstIp,
+ int srcPort, int dstPort, uint64_t timestampNs));
};
class MockIptablesRestore : public IptablesRestoreInterface {
@@ -51,15 +61,19 @@
public:
~MockNFLogListener() override = default;
MOCK_METHOD2(subscribe, netdutils::Status(uint16_t nfLogGroup, const DispatchFn& fn));
+ MOCK_METHOD3(subscribe,
+ netdutils::Status(uint16_t nfLogGroup, uint32_t copyRange, const DispatchFn& fn));
MOCK_METHOD1(unsubscribe, netdutils::Status(uint16_t nfLogGroup));
};
class WakeupControllerTest : public Test {
protected:
WakeupControllerTest() {
- EXPECT_CALL(mListener, subscribe(NetlinkManager::NFLOG_WAKEUP_GROUP, _))
- .WillOnce(DoAll(SaveArg<1>(&mMessageHandler), Return(ok)));
- EXPECT_CALL(mListener, unsubscribe(NetlinkManager::NFLOG_WAKEUP_GROUP)).WillOnce(Return(ok));
+ EXPECT_CALL(mListener,
+ subscribe(NetlinkManager::NFLOG_WAKEUP_GROUP, kDefaultPacketCopyRange, _))
+ .WillOnce(DoAll(SaveArg<2>(&mMessageHandler), Return(ok)));
+ EXPECT_CALL(mListener,
+ unsubscribe(NetlinkManager::NFLOG_WAKEUP_GROUP)).WillOnce(Return(ok));
mController.init(&mListener);
}
@@ -67,14 +81,16 @@
StrictMock<MockIptablesRestore> mIptables;
StrictMock<MockNFLogListener> mListener;
WakeupController mController{
- [this](const std::string& prefix, uid_t uid, gid_t gid, uint64_t timestampNs) {
- mEventListener.onWakeupEvent(prefix, uid, gid, timestampNs);
+ [this](const WakeupController::ReportArgs& args) {
+ mEventListener.onWakeupEvent(args.prefix, args.uid, args.ethertype, args.ipNextHeader,
+ args.dstHw, args.srcIp, args.dstIp, args.srcPort,
+ args.dstPort, args.timestampNs);
},
&mIptables};
NFLogListenerInterface::DispatchFn mMessageHandler;
};
-TEST_F(WakeupControllerTest, msgHandler) {
+TEST_F(WakeupControllerTest, msgHandlerWithPartialAttributes) {
const char kPrefix[] = "test:prefix";
const uid_t kUid = 8734;
const gid_t kGid = 2222;
@@ -96,23 +112,100 @@
msg.uidAttr.nla_type = NFULA_UID;
msg.uidAttr.nla_len = sizeof(msg.uidAttr) + sizeof(msg.uid);
- msg.uid = htobe32(kUid);
+ msg.uid = htonl(kUid);
msg.gidAttr.nla_type = NFULA_GID;
msg.gidAttr.nla_len = sizeof(msg.gidAttr) + sizeof(msg.gid);
- msg.gid = htobe32(kGid);
+ msg.gid = htonl(kGid);
msg.tsAttr.nla_type = NFULA_TIMESTAMP;
msg.tsAttr.nla_len = sizeof(msg.tsAttr) + sizeof(msg.ts);
- msg.ts.tv_sec = htobe32(kTsNs / kNsPerS);
- msg.ts.tv_nsec = htobe32(kTsNs % kNsPerS);
+ msg.ts.tv_sec = htonl(kTsNs / kNsPerS);
+ msg.ts.tv_nsec = htonl(kTsNs % kNsPerS);
msg.prefixAttr.nla_type = NFULA_PREFIX;
msg.prefixAttr.nla_len = sizeof(msg.prefixAttr) + sizeof(msg.prefix);
memcpy(msg.prefix, kPrefix, sizeof(kPrefix));
auto payload = drop(netdutils::makeSlice(msg), offsetof(Msg, uidAttr));
- EXPECT_CALL(mEventListener, onWakeupEvent(kPrefix, kUid, kGid, kTsNs));
+ EXPECT_CALL(mEventListener,
+ onWakeupEvent(kPrefix, kUid, -1, -1, std::vector<uint8_t>(), "", "", -1, -1, kTsNs));
+ mMessageHandler(msg.nlmsg, msg.nfmsg, payload);
+}
+
+TEST_F(WakeupControllerTest, msgHandler) {
+ const char kPrefix[] = "test:prefix";
+ const uid_t kUid = 8734;
+ const gid_t kGid = 2222;
+ const std::vector<uint8_t> kMacAddr = {11, 22, 33, 44, 55, 66};
+ const char* kSrcIpAddr = "192.168.2.1";
+ const char* kDstIpAddr = "192.168.2.23";
+ const uint16_t kEthertype = 0x800;
+ const uint8_t kIpNextHeader = 6;
+ const uint16_t kSrcPort = 1238;
+ const uint16_t kDstPort = 4567;
+ const uint64_t kNsPerS = 1000000000ULL;
+ const uint64_t kTsNs = 9999 + (34 * kNsPerS);
+
+ struct Msg {
+ nlmsghdr nlmsg;
+ nfgenmsg nfmsg;
+ nlattr uidAttr;
+ uid_t uid;
+ nlattr gidAttr;
+ gid_t gid;
+ nlattr tsAttr;
+ timespec ts;
+ nlattr prefixAttr;
+ char prefix[sizeof(kPrefix)];
+ nlattr packetHeaderAttr;
+ struct nfulnl_msg_packet_hdr packetHeader;
+ nlattr hardwareAddrAttr;
+ struct nfulnl_msg_packet_hw hardwareAddr;
+ nlattr packetPayloadAttr;
+ struct iphdr ipHeader;
+ struct tcphdr tcpHeader;
+ } msg = {};
+
+ msg.prefixAttr.nla_type = NFULA_PREFIX;
+ msg.prefixAttr.nla_len = sizeof(msg.prefixAttr) + sizeof(msg.prefix);
+ memcpy(msg.prefix, kPrefix, sizeof(kPrefix));
+
+ msg.uidAttr.nla_type = NFULA_UID;
+ msg.uidAttr.nla_len = sizeof(msg.uidAttr) + sizeof(msg.uid);
+ msg.uid = htonl(kUid);
+
+ msg.gidAttr.nla_type = NFULA_GID;
+ msg.gidAttr.nla_len = sizeof(msg.gidAttr) + sizeof(msg.gid);
+ msg.gid = htonl(kGid);
+
+ msg.tsAttr.nla_type = NFULA_TIMESTAMP;
+ msg.tsAttr.nla_len = sizeof(msg.tsAttr) + sizeof(msg.ts);
+ msg.ts.tv_sec = htonl(kTsNs / kNsPerS);
+ msg.ts.tv_nsec = htonl(kTsNs % kNsPerS);
+
+ msg.packetHeaderAttr.nla_type = NFULA_PACKET_HDR;
+ msg.packetHeaderAttr.nla_len = sizeof(msg.packetHeaderAttr) + sizeof(msg.packetHeader);
+ msg.packetHeader.hw_protocol = htons(kEthertype);
+
+ msg.hardwareAddrAttr.nla_type = NFULA_HWADDR;
+ msg.hardwareAddrAttr.nla_len = sizeof(msg.hardwareAddrAttr) + sizeof(msg.hardwareAddr);
+ msg.hardwareAddr.hw_addrlen = htons(kMacAddr.size());
+ std::copy(kMacAddr.begin(), kMacAddr.end(), msg.hardwareAddr.hw_addr);
+
+ msg.packetPayloadAttr.nla_type = NFULA_PAYLOAD;
+ msg.packetPayloadAttr.nla_len =
+ sizeof(msg.packetPayloadAttr) + sizeof(msg.ipHeader) + sizeof(msg.tcpHeader);
+ msg.ipHeader.protocol = IPPROTO_TCP;
+ msg.ipHeader.ihl = sizeof(msg.ipHeader) / 4; // ipv4 IHL counts 32 bit words.
+ inet_pton(AF_INET, kSrcIpAddr, &msg.ipHeader.saddr);
+ inet_pton(AF_INET, kDstIpAddr, &msg.ipHeader.daddr);
+ msg.tcpHeader.th_sport = htons(kSrcPort);
+ msg.tcpHeader.th_dport = htons(kDstPort);
+
+ auto payload = drop(netdutils::makeSlice(msg), offsetof(Msg, uidAttr));
+ EXPECT_CALL(mEventListener, onWakeupEvent(kPrefix, kUid, kEthertype, kIpNextHeader, kMacAddr,
+ kSrcIpAddr, kDstIpAddr, kSrcPort, kDstPort, kTsNs));
mMessageHandler(msg.nlmsg, msg.nfmsg, payload);
}
@@ -140,7 +233,7 @@
msg.uidAttr.nla_type = 999;
msg.uidAttr.nla_len = sizeof(msg.uidAttr) + sizeof(msg.uid);
- msg.uid = htobe32(kUid);
+ msg.uid = htonl(kUid);
msg.invalid0.nla_type = 0;
msg.invalid0.nla_len = 0;
@@ -149,19 +242,20 @@
msg.gidAttr.nla_type = NFULA_GID;
msg.gidAttr.nla_len = sizeof(msg.gidAttr) + sizeof(msg.gid);
- msg.gid = htobe32(kGid);
+ msg.gid = htonl(kGid);
msg.tsAttr.nla_type = NFULA_TIMESTAMP;
msg.tsAttr.nla_len = sizeof(msg.tsAttr) - 2;
- msg.ts.tv_sec = htobe32(kTsNs / kNsPerS);
- msg.ts.tv_nsec = htobe32(kTsNs % kNsPerS);
+ msg.ts.tv_sec = htonl(kTsNs / kNsPerS);
+ msg.ts.tv_nsec = htonl(kTsNs % kNsPerS);
msg.prefixAttr.nla_type = NFULA_UID;
msg.prefixAttr.nla_len = sizeof(msg.prefixAttr) + sizeof(msg.prefix);
memcpy(msg.prefix, kPrefix, sizeof(kPrefix));
auto payload = drop(netdutils::makeSlice(msg), offsetof(Msg, uidAttr));
- EXPECT_CALL(mEventListener, onWakeupEvent("", 1952805748, kGid, 0));
+ EXPECT_CALL(mEventListener,
+ onWakeupEvent("", 1952805748, -1, -1, std::vector<uint8_t>(), "", "", -1, -1, 0));
mMessageHandler(msg.nlmsg, msg.nfmsg, payload);
}
@@ -182,7 +276,8 @@
const auto expected = std::string(ones, sizeof(ones) - 1);
auto payload = drop(netdutils::makeSlice(msg), offsetof(Msg, prefixAttr));
- EXPECT_CALL(mEventListener, onWakeupEvent(expected, -1, -1, -1));
+ EXPECT_CALL(mEventListener,
+ onWakeupEvent(expected, -1, -1, -1, std::vector<uint8_t>(), "", "", -1, -1, 0));
mMessageHandler(msg.nlmsg, msg.nfmsg, payload);
}
@@ -194,7 +289,7 @@
const char kExpected[] =
"*mangle\n-A wakeupctrl_mangle_INPUT -i test:prefix"
" -j NFLOG --nflog-prefix wlan8 --nflog-group 3 --nflog-threshold 8"
- " -m mark --mark 0x12345678/0x0f0f0f0f -m limit --limit 10/s\nCOMMIT\n";
+ " --nflog-range 60 -m mark --mark 0x12345678/0x0f0f0f0f -m limit --limit 10/s\nCOMMIT\n";
EXPECT_CALL(mIptables, execute(V4V6, kExpected, _)).WillOnce(Return(0));
mController.addInterface(kPrefix, kIfName, kMark, kMask);
}
@@ -207,7 +302,7 @@
const char kExpected[] =
"*mangle\n-D wakeupctrl_mangle_INPUT -i test:prefix"
" -j NFLOG --nflog-prefix wlan8 --nflog-group 3 --nflog-threshold 8"
- " -m mark --mark 0x12345678/0xf0f0f0f0 -m limit --limit 10/s\nCOMMIT\n";
+ " --nflog-range 60 -m mark --mark 0x12345678/0xf0f0f0f0 -m limit --limit 10/s\nCOMMIT\n";
EXPECT_CALL(mIptables, execute(V4V6, kExpected, _)).WillOnce(Return(0));
mController.delInterface(kPrefix, kIfName, kMark, kMask);
}
diff --git a/server/binder/android/net/metrics/INetdEventListener.aidl b/server/binder/android/net/metrics/INetdEventListener.aidl
index 7f4a9e4..2601038 100644
--- a/server/binder/android/net/metrics/INetdEventListener.aidl
+++ b/server/binder/android/net/metrics/INetdEventListener.aidl
@@ -64,10 +64,18 @@
/**
* Logs a single RX packet which caused the main CPU to exit sleep state.
* @param prefix arbitrary string provided via wakeupAddInterface()
- * @param UID of the destination process or -1 if no UID is available.
- * @param GID of the destination process or -1 if no GID is available.
- * @param receive timestamp for the offending packet. In units of nanoseconds and
+ * @param uid UID of the destination process or -1 if no UID is available.
+ * @param ethertype of the RX packet encoded in an int in native order, or -1 if not available.
+ * @param ipNextHeader ip protocol of the RX packet as IPPROTO_* number,
+ or -1 if the packet was not IPv4 or IPv6.
+ * @param dstHw destination hardware address, or 0 if not available.
+ * @param srcIp source IP address, or null if not available.
+ * @param dstIp destination IP address, or null if not available.
+ * @param srcPort src port of RX packet in native order, or -1 if the packet was not UDP or TCP.
+ * @param dstPort dst port of RX packet in native order, or -1 if the packet was not UDP or TCP.
+ * @param timestampNs receive timestamp for the offending packet. In units of nanoseconds and
* synchronized to CLOCK_MONOTONIC.
*/
- void onWakeupEvent(String prefix, int uid, int gid, long timestampNs);
+ void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader, in byte[] dstHw,
+ String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs);
}