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