blob: 05e899cf272281793b0ab9ca6ac474c78ae2fb65 [file] [log] [blame]
/*
* 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