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 <endian.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: 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 74 ~NFLogListenerTest() { 75 EXPECT_CALL(*mNLListener, unsubscribe(kNFLogPacketMsgType)).WillOnce(Return(ok)); 76 EXPECT_CALL(*mNLListener, unsubscribe(kNetlinkMsgDoneType)).WillOnce(Return(ok)); 77 } 78 79 static StatusOr<size_t> sendOk(const Slice buf) { return buf.size(); } 80 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 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 = htobe16(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 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 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 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, be16toh(nfmsg.res_id)); 125 ++invocations; 126 }; 127 subscribe(kType, dispatchFn); 128 sendEmptyMsg(kType); 129 EXPECT_EQ(1, invocations); 130 } 131 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