You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
216 lines
7.1 KiB
216 lines
7.1 KiB
/* |
|
* 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 <linux/netfilter/nfnetlink_log.h> |
|
|
|
#include <gmock/gmock.h> |
|
#include <gtest/gtest.h> |
|
|
|
#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<MockNetdEventListener> mEventListener; |
|
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); |
|
}, |
|
&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
|
|
|