1 /*
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 <atomic>
18 #include <deque>
19 #include <iostream>
20 #include <mutex>
21
22 #include <arpa/inet.h>
23 #include <gmock/gmock.h>
24 #include <gtest/gtest.h>
25 #include <linux/netfilter/nfnetlink_log.h>
26
27 #include <netdutils/MockSyscalls.h>
28 #include "NFLogListener.h"
29
30 using ::testing::ByMove;
31 using ::testing::Exactly;
32 using ::testing::Invoke;
33 using ::testing::Mock;
34 using ::testing::SaveArg;
35 using ::testing::DoAll;
36 using ::testing::Return;
37 using ::testing::StrictMock;
38 using ::testing::_;
39
40 namespace android {
41 namespace net {
42
43 using netdutils::Fd;
44 using netdutils::Slice;
45 using netdutils::StatusOr;
46 using netdutils::UniqueFd;
47 using netdutils::forEachNetlinkAttribute;
48 using netdutils::makeSlice;
49 using netdutils::status::ok;
50
51 constexpr int kNFLogPacketMsgType = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_PACKET;
52 constexpr int kNetlinkMsgDoneType = (NFNL_SUBSYS_NONE << 8) | NLMSG_DONE;
53
54 class MockNetlinkListener : public NetlinkListenerInterface {
55 public:
56 ~MockNetlinkListener() override = default;
57
58 MOCK_METHOD1(send, netdutils::Status(const netdutils::Slice msg));
59 MOCK_METHOD2(subscribe, netdutils::Status(uint16_t type, const DispatchFn& fn));
60 MOCK_METHOD1(unsubscribe, netdutils::Status(uint16_t type));
61 MOCK_METHOD0(join, void());
62 };
63
64 class NFLogListenerTest : public testing::Test {
65 protected:
NFLogListenerTest()66 NFLogListenerTest() {
67 EXPECT_CALL(*mNLListener, subscribe(kNFLogPacketMsgType, _))
68 .WillOnce(DoAll(SaveArg<1>(&mPacketFn), Return(ok)));
69 EXPECT_CALL(*mNLListener, subscribe(kNetlinkMsgDoneType, _))
70 .WillOnce(DoAll(SaveArg<1>(&mDoneFn), Return(ok)));
71 mListener.reset(new NFLogListener(mNLListener));
72 }
73
~NFLogListenerTest()74 ~NFLogListenerTest() {
75 EXPECT_CALL(*mNLListener, unsubscribe(kNFLogPacketMsgType)).WillOnce(Return(ok));
76 EXPECT_CALL(*mNLListener, unsubscribe(kNetlinkMsgDoneType)).WillOnce(Return(ok));
77 }
78
sendOk(const Slice buf)79 static StatusOr<size_t> sendOk(const Slice buf) { return buf.size(); }
80
subscribe(uint16_t type,NFLogListenerInterface::DispatchFn fn)81 void subscribe(uint16_t type, NFLogListenerInterface::DispatchFn fn) {
82 // Two sends for cfgCmdBind() & cfgMode(), one send at destruction time for cfgCmdUnbind()
83 EXPECT_CALL(*mNLListener, send(_)).Times(Exactly(3)).WillRepeatedly(Invoke(sendOk));
84 mListener->subscribe(type, fn);
85 }
86
sendEmptyMsg(uint16_t type)87 void sendEmptyMsg(uint16_t type) {
88 struct {
89 nlmsghdr nlmsg;
90 nfgenmsg nfmsg;
91 } msg = {};
92
93 msg.nlmsg.nlmsg_type = kNFLogPacketMsgType;
94 msg.nlmsg.nlmsg_len = sizeof(msg);
95 msg.nfmsg.res_id = htons(type);
96 mPacketFn(msg.nlmsg, drop(makeSlice(msg), sizeof(msg.nlmsg)));
97 }
98
99 NetlinkListenerInterface::DispatchFn mPacketFn;
100 NetlinkListenerInterface::DispatchFn mDoneFn;
101 std::shared_ptr<StrictMock<MockNetlinkListener>> mNLListener{
102 new StrictMock<MockNetlinkListener>()};
103 std::unique_ptr<NFLogListener> mListener;
104 };
105
TEST_F(NFLogListenerTest,subscribe)106 TEST_F(NFLogListenerTest, subscribe) {
107 constexpr uint16_t kType = 38;
108 const auto dispatchFn = [](const nlmsghdr&, const nfgenmsg&, const netdutils::Slice) {};
109 subscribe(kType, dispatchFn);
110 }
111
TEST_F(NFLogListenerTest,nlmsgDone)112 TEST_F(NFLogListenerTest, nlmsgDone) {
113 constexpr uint16_t kType = 38;
114 const auto dispatchFn = [](const nlmsghdr&, const nfgenmsg&, const netdutils::Slice) {};
115 subscribe(kType, dispatchFn);
116 mDoneFn({}, {});
117 }
118
TEST_F(NFLogListenerTest,dispatchOk)119 TEST_F(NFLogListenerTest, dispatchOk) {
120 int invocations = 0;
121 constexpr uint16_t kType = 38;
122 const auto dispatchFn = [&invocations, kType](const nlmsghdr&, const nfgenmsg& nfmsg,
123 const netdutils::Slice) {
124 EXPECT_EQ(kType, ntohs(nfmsg.res_id));
125 ++invocations;
126 };
127 subscribe(kType, dispatchFn);
128 sendEmptyMsg(kType);
129 EXPECT_EQ(1, invocations);
130 }
131
TEST_F(NFLogListenerTest,dispatchUnknownType)132 TEST_F(NFLogListenerTest, dispatchUnknownType) {
133 constexpr uint16_t kType = 38;
134 constexpr uint16_t kBadType = kType + 1;
135 const auto dispatchFn = [](const nlmsghdr&, const nfgenmsg&, const netdutils::Slice) {
136 // Expect no invocations
137 ASSERT_TRUE(false);
138 };
139 subscribe(kType, dispatchFn);
140 sendEmptyMsg(kBadType);
141 }
142
143 } // namespace net
144 } // namespace android
145