/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include "NetlinkManager.h" #include "WakeupController.h" using ::testing::StrictMock; using ::testing::Test; using ::testing::DoAll; using ::testing::SaveArg; using ::testing::Return; using ::testing::_; namespace android { namespace net { const uint32_t kDefaultPacketCopyRange = WakeupController::kDefaultPacketCopyRange; using netdutils::status::ok; class MockNetdEventListener { public: MOCK_METHOD10(onWakeupEvent, void(const std::string& prefix, int uid, int ether, int ipNextHeader, const std::vector& dstHw, const std::string& srcIp, const std::string& dstIp, int srcPort, int dstPort, uint64_t timestampNs)); }; class MockIptablesRestore : public IptablesRestoreInterface { public: ~MockIptablesRestore() override = default; MOCK_METHOD3(execute, int(const IptablesTarget target, const std::string& commands, std::string* output)); }; class MockNFLogListener : public NFLogListenerInterface { 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, kDefaultPacketCopyRange, _)) .WillOnce(DoAll(SaveArg<2>(&mMessageHandler), Return(ok))); EXPECT_CALL(mListener, unsubscribe(NetlinkManager::NFLOG_WAKEUP_GROUP)).WillOnce(Return(ok)); EXPECT_OK(mController.init(&mListener)); } StrictMock mEventListener; StrictMock mIptables; StrictMock mListener; WakeupController mController{ [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, msgHandlerWithPartialAttributes) { const char kPrefix[] = "test:prefix"; const uid_t kUid = 8734; const gid_t kGid = 2222; 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)]; } msg = {}; 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.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, -1, -1, std::vector(), "", "", -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 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); } TEST_F(WakeupControllerTest, badAttr) { const char kPrefix[] = "test:prefix"; const uid_t kUid = 8734; const gid_t kGid = 2222; const uint64_t kNsPerS = 1000000000ULL; const uint64_t kTsNs = 9999 + (34 * kNsPerS); struct Msg { nlmsghdr nlmsg; nfgenmsg nfmsg; nlattr uidAttr; uid_t uid; nlattr invalid0; nlattr invalid1; nlattr gidAttr; gid_t gid; nlattr tsAttr; timespec ts; nlattr prefixAttr; char prefix[sizeof(kPrefix)]; } msg = {}; msg.uidAttr.nla_type = 999; msg.uidAttr.nla_len = sizeof(msg.uidAttr) + sizeof(msg.uid); msg.uid = htonl(kUid); msg.invalid0.nla_type = 0; msg.invalid0.nla_len = 0; msg.invalid1.nla_type = 0; msg.invalid1.nla_len = 1; 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) - 2; 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, -1, -1, std::vector(), "", "", -1, -1, 0)); mMessageHandler(msg.nlmsg, msg.nfmsg, payload); } TEST_F(WakeupControllerTest, unterminatedString) { char ones[20] = {}; memset(ones, 1, sizeof(ones)); struct Msg { nlmsghdr nlmsg; nfgenmsg nfmsg; nlattr prefixAttr; char prefix[sizeof(ones)]; } msg = {}; msg.prefixAttr.nla_type = NFULA_PREFIX; msg.prefixAttr.nla_len = sizeof(msg.prefixAttr) + sizeof(msg.prefix); memcpy(msg.prefix, ones, sizeof(ones)); 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, std::vector(), "", "", -1, -1, 0)); mMessageHandler(msg.nlmsg, msg.nfmsg, payload); } TEST_F(WakeupControllerTest, addInterface) { const char kPrefix[] = "test:prefix"; const char kIfName[] = "wlan8"; const uint32_t kMark = 0x12345678; const uint32_t kMask = 0x0F0F0F0F; const char kExpected[] = "*mangle\n" "-A wakeupctrl_mangle_INPUT -i test:prefix" " -m mark --mark 0x12345678/0x0f0f0f0f -m limit --limit 10/s" " -j NFLOG --nflog-prefix wlan8 --nflog-group 3 --nflog-threshold 8\n" "COMMIT\n"; EXPECT_CALL(mIptables, execute(V4V6, kExpected, _)).WillOnce(Return(0)); EXPECT_OK(mController.addInterface(kPrefix, kIfName, kMark, kMask)); } TEST_F(WakeupControllerTest, delInterface) { const char kPrefix[] = "test:prefix"; const char kIfName[] = "wlan8"; const uint32_t kMark = 0x12345678; const uint32_t kMask = 0xF0F0F0F0; const char kExpected[] = "*mangle\n" "-D wakeupctrl_mangle_INPUT -i test:prefix" " -m mark --mark 0x12345678/0xf0f0f0f0 -m limit --limit 10/s" " -j NFLOG --nflog-prefix wlan8 --nflog-group 3 --nflog-threshold 8\n" "COMMIT\n"; EXPECT_CALL(mIptables, execute(V4V6, kExpected, _)).WillOnce(Return(0)); EXPECT_OK(mController.delInterface(kPrefix, kIfName, kMark, kMask)); } } // namespace net } // namespace android