Home | History | Annotate | Download | only in server
      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