/* * 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 "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 { using netdutils::status::ok; class MockNetdEventListener { public: MOCK_METHOD4(onWakeupEvent, void(const std::string& prefix, uid_t uid, gid_t gid, 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_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)); mController.init(&mListener); } StrictMock mEventListener; StrictMock mIptables; StrictMock mListener; WakeupController mController{ [this](const std::string& prefix, uid_t uid, gid_t gid, uint64_t timestampNs) { mEventListener.onWakeupEvent(prefix, uid, gid, timestampNs); }, &mIptables}; NFLogListenerInterface::DispatchFn mMessageHandler; }; TEST_F(WakeupControllerTest, msgHandler) { 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 = htobe32(kUid); msg.gidAttr.nla_type = NFULA_GID; msg.gidAttr.nla_len = sizeof(msg.gidAttr) + sizeof(msg.gid); msg.gid = htobe32(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.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)); 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 = htobe32(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 = htobe32(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.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)); 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)); 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" " -j NFLOG --nflog-prefix wlan8 --nflog-group 3 --nflog-threshold 8" " -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); } 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" " -j NFLOG --nflog-prefix wlan8 --nflog-group 3 --nflog-threshold 8" " -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); } } // namespace net } // namespace android