blob: f7812e515f6b790eb1ef833fe0d699fbbe13ba42 [file] [log] [blame]
Joel Scherpelz08b84cd2017-05-22 13:11:54 +09001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <linux/netfilter/nfnetlink_log.h>
18
Hugo Benichie874b7f2017-10-12 21:34:46 +090019#include <arpa/inet.h>
20#include <sys/socket.h>
21#include <netinet/in.h>
22#include <netinet/ip.h>
23#include <netinet/tcp.h>
24
Joel Scherpelz08b84cd2017-05-22 13:11:54 +090025#include <gmock/gmock.h>
26#include <gtest/gtest.h>
27
28#include "NetlinkManager.h"
29#include "WakeupController.h"
30
31using ::testing::StrictMock;
32using ::testing::Test;
33using ::testing::DoAll;
34using ::testing::SaveArg;
35using ::testing::Return;
36using ::testing::_;
37
38namespace android {
39namespace net {
40
Hugo Benichie874b7f2017-10-12 21:34:46 +090041const uint32_t kDefaultPacketCopyRange = WakeupController::kDefaultPacketCopyRange;
42
Joel Scherpelz08b84cd2017-05-22 13:11:54 +090043using netdutils::status::ok;
44
45class MockNetdEventListener {
46 public:
Hugo Benichie874b7f2017-10-12 21:34:46 +090047 MOCK_METHOD10(onWakeupEvent, void(
48 const std::string& prefix, int uid, int ether, int ipNextHeader,
49 std::vector<uint8_t> dstHw, const std::string& srcIp, const std::string& dstIp,
50 int srcPort, int dstPort, uint64_t timestampNs));
Joel Scherpelz08b84cd2017-05-22 13:11:54 +090051};
52
53class MockIptablesRestore : public IptablesRestoreInterface {
54 public:
55 ~MockIptablesRestore() override = default;
56 MOCK_METHOD3(execute, int(const IptablesTarget target, const std::string& commands,
57 std::string* output));
58};
59
60class MockNFLogListener : public NFLogListenerInterface {
61 public:
62 ~MockNFLogListener() override = default;
63 MOCK_METHOD2(subscribe, netdutils::Status(uint16_t nfLogGroup, const DispatchFn& fn));
Hugo Benichie874b7f2017-10-12 21:34:46 +090064 MOCK_METHOD3(subscribe,
65 netdutils::Status(uint16_t nfLogGroup, uint32_t copyRange, const DispatchFn& fn));
Joel Scherpelz08b84cd2017-05-22 13:11:54 +090066 MOCK_METHOD1(unsubscribe, netdutils::Status(uint16_t nfLogGroup));
67};
68
69class WakeupControllerTest : public Test {
70 protected:
71 WakeupControllerTest() {
Hugo Benichie874b7f2017-10-12 21:34:46 +090072 EXPECT_CALL(mListener,
73 subscribe(NetlinkManager::NFLOG_WAKEUP_GROUP, kDefaultPacketCopyRange, _))
74 .WillOnce(DoAll(SaveArg<2>(&mMessageHandler), Return(ok)));
75 EXPECT_CALL(mListener,
76 unsubscribe(NetlinkManager::NFLOG_WAKEUP_GROUP)).WillOnce(Return(ok));
Joel Scherpelz08b84cd2017-05-22 13:11:54 +090077 mController.init(&mListener);
78 }
79
80 StrictMock<MockNetdEventListener> mEventListener;
81 StrictMock<MockIptablesRestore> mIptables;
82 StrictMock<MockNFLogListener> mListener;
83 WakeupController mController{
Hugo Benichie874b7f2017-10-12 21:34:46 +090084 [this](const WakeupController::ReportArgs& args) {
85 mEventListener.onWakeupEvent(args.prefix, args.uid, args.ethertype, args.ipNextHeader,
86 args.dstHw, args.srcIp, args.dstIp, args.srcPort,
87 args.dstPort, args.timestampNs);
Joel Scherpelz08b84cd2017-05-22 13:11:54 +090088 },
89 &mIptables};
90 NFLogListenerInterface::DispatchFn mMessageHandler;
91};
92
Hugo Benichie874b7f2017-10-12 21:34:46 +090093TEST_F(WakeupControllerTest, msgHandlerWithPartialAttributes) {
Joel Scherpelz08b84cd2017-05-22 13:11:54 +090094 const char kPrefix[] = "test:prefix";
95 const uid_t kUid = 8734;
96 const gid_t kGid = 2222;
97 const uint64_t kNsPerS = 1000000000ULL;
98 const uint64_t kTsNs = 9999 + (34 * kNsPerS);
99
100 struct Msg {
101 nlmsghdr nlmsg;
102 nfgenmsg nfmsg;
103 nlattr uidAttr;
104 uid_t uid;
105 nlattr gidAttr;
106 gid_t gid;
107 nlattr tsAttr;
108 timespec ts;
109 nlattr prefixAttr;
110 char prefix[sizeof(kPrefix)];
111 } msg = {};
112
113 msg.uidAttr.nla_type = NFULA_UID;
114 msg.uidAttr.nla_len = sizeof(msg.uidAttr) + sizeof(msg.uid);
Hugo Benichie874b7f2017-10-12 21:34:46 +0900115 msg.uid = htonl(kUid);
Joel Scherpelz08b84cd2017-05-22 13:11:54 +0900116
117 msg.gidAttr.nla_type = NFULA_GID;
118 msg.gidAttr.nla_len = sizeof(msg.gidAttr) + sizeof(msg.gid);
Hugo Benichie874b7f2017-10-12 21:34:46 +0900119 msg.gid = htonl(kGid);
Joel Scherpelz08b84cd2017-05-22 13:11:54 +0900120
121 msg.tsAttr.nla_type = NFULA_TIMESTAMP;
122 msg.tsAttr.nla_len = sizeof(msg.tsAttr) + sizeof(msg.ts);
Hugo Benichie874b7f2017-10-12 21:34:46 +0900123 msg.ts.tv_sec = htonl(kTsNs / kNsPerS);
124 msg.ts.tv_nsec = htonl(kTsNs % kNsPerS);
Joel Scherpelz08b84cd2017-05-22 13:11:54 +0900125
126 msg.prefixAttr.nla_type = NFULA_PREFIX;
127 msg.prefixAttr.nla_len = sizeof(msg.prefixAttr) + sizeof(msg.prefix);
128 memcpy(msg.prefix, kPrefix, sizeof(kPrefix));
129
130 auto payload = drop(netdutils::makeSlice(msg), offsetof(Msg, uidAttr));
Hugo Benichie874b7f2017-10-12 21:34:46 +0900131 EXPECT_CALL(mEventListener,
132 onWakeupEvent(kPrefix, kUid, -1, -1, std::vector<uint8_t>(), "", "", -1, -1, kTsNs));
133 mMessageHandler(msg.nlmsg, msg.nfmsg, payload);
134}
135
136TEST_F(WakeupControllerTest, msgHandler) {
137 const char kPrefix[] = "test:prefix";
138 const uid_t kUid = 8734;
139 const gid_t kGid = 2222;
140 const std::vector<uint8_t> kMacAddr = {11, 22, 33, 44, 55, 66};
141 const char* kSrcIpAddr = "192.168.2.1";
142 const char* kDstIpAddr = "192.168.2.23";
143 const uint16_t kEthertype = 0x800;
144 const uint8_t kIpNextHeader = 6;
145 const uint16_t kSrcPort = 1238;
146 const uint16_t kDstPort = 4567;
147 const uint64_t kNsPerS = 1000000000ULL;
148 const uint64_t kTsNs = 9999 + (34 * kNsPerS);
149
150 struct Msg {
151 nlmsghdr nlmsg;
152 nfgenmsg nfmsg;
153 nlattr uidAttr;
154 uid_t uid;
155 nlattr gidAttr;
156 gid_t gid;
157 nlattr tsAttr;
158 timespec ts;
159 nlattr prefixAttr;
160 char prefix[sizeof(kPrefix)];
161 nlattr packetHeaderAttr;
162 struct nfulnl_msg_packet_hdr packetHeader;
163 nlattr hardwareAddrAttr;
164 struct nfulnl_msg_packet_hw hardwareAddr;
165 nlattr packetPayloadAttr;
166 struct iphdr ipHeader;
167 struct tcphdr tcpHeader;
168 } msg = {};
169
170 msg.prefixAttr.nla_type = NFULA_PREFIX;
171 msg.prefixAttr.nla_len = sizeof(msg.prefixAttr) + sizeof(msg.prefix);
172 memcpy(msg.prefix, kPrefix, sizeof(kPrefix));
173
174 msg.uidAttr.nla_type = NFULA_UID;
175 msg.uidAttr.nla_len = sizeof(msg.uidAttr) + sizeof(msg.uid);
176 msg.uid = htonl(kUid);
177
178 msg.gidAttr.nla_type = NFULA_GID;
179 msg.gidAttr.nla_len = sizeof(msg.gidAttr) + sizeof(msg.gid);
180 msg.gid = htonl(kGid);
181
182 msg.tsAttr.nla_type = NFULA_TIMESTAMP;
183 msg.tsAttr.nla_len = sizeof(msg.tsAttr) + sizeof(msg.ts);
184 msg.ts.tv_sec = htonl(kTsNs / kNsPerS);
185 msg.ts.tv_nsec = htonl(kTsNs % kNsPerS);
186
187 msg.packetHeaderAttr.nla_type = NFULA_PACKET_HDR;
188 msg.packetHeaderAttr.nla_len = sizeof(msg.packetHeaderAttr) + sizeof(msg.packetHeader);
189 msg.packetHeader.hw_protocol = htons(kEthertype);
190
191 msg.hardwareAddrAttr.nla_type = NFULA_HWADDR;
192 msg.hardwareAddrAttr.nla_len = sizeof(msg.hardwareAddrAttr) + sizeof(msg.hardwareAddr);
193 msg.hardwareAddr.hw_addrlen = htons(kMacAddr.size());
194 std::copy(kMacAddr.begin(), kMacAddr.end(), msg.hardwareAddr.hw_addr);
195
196 msg.packetPayloadAttr.nla_type = NFULA_PAYLOAD;
197 msg.packetPayloadAttr.nla_len =
198 sizeof(msg.packetPayloadAttr) + sizeof(msg.ipHeader) + sizeof(msg.tcpHeader);
199 msg.ipHeader.protocol = IPPROTO_TCP;
200 msg.ipHeader.ihl = sizeof(msg.ipHeader) / 4; // ipv4 IHL counts 32 bit words.
201 inet_pton(AF_INET, kSrcIpAddr, &msg.ipHeader.saddr);
202 inet_pton(AF_INET, kDstIpAddr, &msg.ipHeader.daddr);
203 msg.tcpHeader.th_sport = htons(kSrcPort);
204 msg.tcpHeader.th_dport = htons(kDstPort);
205
206 auto payload = drop(netdutils::makeSlice(msg), offsetof(Msg, uidAttr));
207 EXPECT_CALL(mEventListener, onWakeupEvent(kPrefix, kUid, kEthertype, kIpNextHeader, kMacAddr,
208 kSrcIpAddr, kDstIpAddr, kSrcPort, kDstPort, kTsNs));
Joel Scherpelz08b84cd2017-05-22 13:11:54 +0900209 mMessageHandler(msg.nlmsg, msg.nfmsg, payload);
210}
211
212TEST_F(WakeupControllerTest, badAttr) {
213 const char kPrefix[] = "test:prefix";
214 const uid_t kUid = 8734;
215 const gid_t kGid = 2222;
216 const uint64_t kNsPerS = 1000000000ULL;
217 const uint64_t kTsNs = 9999 + (34 * kNsPerS);
218
219 struct Msg {
220 nlmsghdr nlmsg;
221 nfgenmsg nfmsg;
222 nlattr uidAttr;
223 uid_t uid;
224 nlattr invalid0;
225 nlattr invalid1;
226 nlattr gidAttr;
227 gid_t gid;
228 nlattr tsAttr;
229 timespec ts;
230 nlattr prefixAttr;
231 char prefix[sizeof(kPrefix)];
232 } msg = {};
233
234 msg.uidAttr.nla_type = 999;
235 msg.uidAttr.nla_len = sizeof(msg.uidAttr) + sizeof(msg.uid);
Hugo Benichie874b7f2017-10-12 21:34:46 +0900236 msg.uid = htonl(kUid);
Joel Scherpelz08b84cd2017-05-22 13:11:54 +0900237
238 msg.invalid0.nla_type = 0;
239 msg.invalid0.nla_len = 0;
240 msg.invalid1.nla_type = 0;
241 msg.invalid1.nla_len = 1;
242
243 msg.gidAttr.nla_type = NFULA_GID;
244 msg.gidAttr.nla_len = sizeof(msg.gidAttr) + sizeof(msg.gid);
Hugo Benichie874b7f2017-10-12 21:34:46 +0900245 msg.gid = htonl(kGid);
Joel Scherpelz08b84cd2017-05-22 13:11:54 +0900246
247 msg.tsAttr.nla_type = NFULA_TIMESTAMP;
248 msg.tsAttr.nla_len = sizeof(msg.tsAttr) - 2;
Hugo Benichie874b7f2017-10-12 21:34:46 +0900249 msg.ts.tv_sec = htonl(kTsNs / kNsPerS);
250 msg.ts.tv_nsec = htonl(kTsNs % kNsPerS);
Joel Scherpelz08b84cd2017-05-22 13:11:54 +0900251
252 msg.prefixAttr.nla_type = NFULA_UID;
253 msg.prefixAttr.nla_len = sizeof(msg.prefixAttr) + sizeof(msg.prefix);
254 memcpy(msg.prefix, kPrefix, sizeof(kPrefix));
255
256 auto payload = drop(netdutils::makeSlice(msg), offsetof(Msg, uidAttr));
Hugo Benichie874b7f2017-10-12 21:34:46 +0900257 EXPECT_CALL(mEventListener,
258 onWakeupEvent("", 1952805748, -1, -1, std::vector<uint8_t>(), "", "", -1, -1, 0));
Joel Scherpelz08b84cd2017-05-22 13:11:54 +0900259 mMessageHandler(msg.nlmsg, msg.nfmsg, payload);
260}
261
262TEST_F(WakeupControllerTest, unterminatedString) {
263 char ones[20] = {};
264 memset(ones, 1, sizeof(ones));
265
266 struct Msg {
267 nlmsghdr nlmsg;
268 nfgenmsg nfmsg;
269 nlattr prefixAttr;
270 char prefix[sizeof(ones)];
271 } msg = {};
272
273 msg.prefixAttr.nla_type = NFULA_PREFIX;
274 msg.prefixAttr.nla_len = sizeof(msg.prefixAttr) + sizeof(msg.prefix);
275 memcpy(msg.prefix, ones, sizeof(ones));
276
277 const auto expected = std::string(ones, sizeof(ones) - 1);
278 auto payload = drop(netdutils::makeSlice(msg), offsetof(Msg, prefixAttr));
Hugo Benichie874b7f2017-10-12 21:34:46 +0900279 EXPECT_CALL(mEventListener,
280 onWakeupEvent(expected, -1, -1, -1, std::vector<uint8_t>(), "", "", -1, -1, 0));
Joel Scherpelz08b84cd2017-05-22 13:11:54 +0900281 mMessageHandler(msg.nlmsg, msg.nfmsg, payload);
282}
283
284TEST_F(WakeupControllerTest, addInterface) {
285 const char kPrefix[] = "test:prefix";
286 const char kIfName[] = "wlan8";
287 const uint32_t kMark = 0x12345678;
288 const uint32_t kMask = 0x0F0F0F0F;
289 const char kExpected[] =
290 "*mangle\n-A wakeupctrl_mangle_INPUT -i test:prefix"
291 " -j NFLOG --nflog-prefix wlan8 --nflog-group 3 --nflog-threshold 8"
Hugo Benichie874b7f2017-10-12 21:34:46 +0900292 " --nflog-range 60 -m mark --mark 0x12345678/0x0f0f0f0f -m limit --limit 10/s\nCOMMIT\n";
Joel Scherpelz08b84cd2017-05-22 13:11:54 +0900293 EXPECT_CALL(mIptables, execute(V4V6, kExpected, _)).WillOnce(Return(0));
294 mController.addInterface(kPrefix, kIfName, kMark, kMask);
295}
296
297TEST_F(WakeupControllerTest, delInterface) {
298 const char kPrefix[] = "test:prefix";
299 const char kIfName[] = "wlan8";
300 const uint32_t kMark = 0x12345678;
301 const uint32_t kMask = 0xF0F0F0F0;
302 const char kExpected[] =
303 "*mangle\n-D wakeupctrl_mangle_INPUT -i test:prefix"
304 " -j NFLOG --nflog-prefix wlan8 --nflog-group 3 --nflog-threshold 8"
Hugo Benichie874b7f2017-10-12 21:34:46 +0900305 " --nflog-range 60 -m mark --mark 0x12345678/0xf0f0f0f0 -m limit --limit 10/s\nCOMMIT\n";
Joel Scherpelz08b84cd2017-05-22 13:11:54 +0900306 EXPECT_CALL(mIptables, execute(V4V6, kExpected, _)).WillOnce(Return(0));
307 mController.delInterface(kPrefix, kIfName, kMark, kMask);
308}
309
310} // namespace net
311} // namespace android