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 #define LOG_TAG "NFLogListener" 18 19 #include <sstream> 20 #include <vector> 21 22 #include <arpa/inet.h> 23 #include <linux/netfilter/nfnetlink_log.h> 24 25 #include <cutils/log.h> 26 #include <netdutils/Misc.h> 27 #include <netdutils/Netfilter.h> 28 #include <netdutils/Syscalls.h> 29 30 #include "NFLogListener.h" 31 32 namespace android { 33 namespace net { 34 35 using netdutils::Slice; 36 using netdutils::Status; 37 using netdutils::StatusOr; 38 using netdutils::UniqueFd; 39 using netdutils::Status; 40 using netdutils::makeSlice; 41 using netdutils::sSyscalls; 42 using netdutils::findWithDefault; 43 using netdutils::status::ok; 44 using netdutils::extract; 45 46 constexpr int kNFLogConfigMsgType = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG; 47 constexpr int kNFLogPacketMsgType = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_PACKET; 48 constexpr int kNetlinkDoneMsgType = (NFNL_SUBSYS_NONE << 8) | NLMSG_DONE; 49 constexpr size_t kDefaultPacketRange = 0; 50 51 namespace { 52 53 const NFLogListener::DispatchFn kDefaultDispatchFn = [](const nlmsghdr& nlmsg, 54 const nfgenmsg& nfmsg, const Slice msg) { 55 std::stringstream ss; 56 ss << nlmsg << " " << nfmsg << " " << msg << " " << netdutils::toHex(msg, 32); 57 ALOGE("unhandled nflog message: %s", ss.str().c_str()); 58 }; 59 60 using SendFn = std::function<Status(const Slice msg)>; 61 62 // Required incantation? 63 Status cfgCmdPfUnbind(const SendFn& send) { 64 struct { 65 nlmsghdr nlhdr; 66 nfgenmsg nfhdr; 67 nfattr attr; 68 nfulnl_msg_config_cmd cmd; 69 } __attribute__((packed)) msg = {}; 70 71 msg.nlhdr.nlmsg_len = sizeof(msg); 72 msg.nlhdr.nlmsg_type = kNFLogConfigMsgType; 73 msg.nlhdr.nlmsg_flags = NLM_F_REQUEST; 74 msg.nfhdr.nfgen_family = AF_UNSPEC; 75 msg.attr.nfa_len = sizeof(msg.attr) + sizeof(msg.cmd); 76 msg.attr.nfa_type = NFULA_CFG_CMD; 77 msg.cmd.command = NFULNL_CFG_CMD_PF_UNBIND; 78 return send(makeSlice(msg)); 79 } 80 81 // Control delivery mode for NFLOG messages marked with nfLogGroup. 82 // range controls maximum bytes to copy 83 // mode must be one of: NFULNL_COPY_NONE, NFULNL_COPY_META, NFULNL_COPY_PACKET 84 Status cfgMode(const SendFn& send, uint16_t nfLogGroup, uint32_t range, uint8_t mode) { 85 struct { 86 nlmsghdr nlhdr; 87 nfgenmsg nfhdr; 88 nfattr attr; 89 nfulnl_msg_config_mode mode; 90 } __attribute__((packed)) msg = {}; 91 92 msg.nlhdr.nlmsg_len = sizeof(msg); 93 msg.nlhdr.nlmsg_type = kNFLogConfigMsgType; 94 msg.nlhdr.nlmsg_flags = NLM_F_REQUEST; 95 msg.nfhdr.nfgen_family = AF_UNSPEC; 96 msg.nfhdr.res_id = htons(nfLogGroup); 97 msg.attr.nfa_len = sizeof(msg.attr) + sizeof(msg.mode); 98 msg.attr.nfa_type = NFULA_CFG_MODE; 99 msg.mode.copy_mode = mode; 100 msg.mode.copy_range = htonl(range); 101 return send(makeSlice(msg)); 102 } 103 104 // Request that NFLOG messages marked with nfLogGroup are delivered to this socket 105 Status cfgCmdBind(const SendFn& send, uint16_t nfLogGroup) { 106 struct { 107 nlmsghdr nlhdr; 108 nfgenmsg nfhdr; 109 nfattr attr; 110 nfulnl_msg_config_cmd cmd; 111 } __attribute__((packed)) msg = {}; 112 113 msg.nlhdr.nlmsg_len = sizeof(msg); 114 msg.nlhdr.nlmsg_type = kNFLogConfigMsgType; 115 msg.nlhdr.nlmsg_flags = NLM_F_REQUEST; 116 msg.nfhdr.nfgen_family = AF_UNSPEC; 117 msg.nfhdr.res_id = htons(nfLogGroup); 118 msg.attr.nfa_len = sizeof(msg.attr) + sizeof(msg.cmd); 119 msg.attr.nfa_type = NFULA_CFG_CMD; 120 msg.cmd.command = NFULNL_CFG_CMD_BIND; 121 return send(makeSlice(msg)); 122 } 123 124 // Request that NFLOG messages marked with nfLogGroup are not delivered to this socket 125 Status cfgCmdUnbind(const SendFn& send, uint16_t nfLogGroup) { 126 struct { 127 nlmsghdr nlhdr; 128 nfgenmsg nfhdr; 129 nfattr attr; 130 nfulnl_msg_config_cmd cmd; 131 } __attribute__((packed)) msg = {}; 132 133 msg.nlhdr.nlmsg_len = sizeof(msg); 134 msg.nlhdr.nlmsg_type = kNFLogConfigMsgType; 135 msg.nlhdr.nlmsg_flags = NLM_F_REQUEST; 136 msg.nfhdr.nfgen_family = AF_UNSPEC; 137 msg.nfhdr.res_id = htons(nfLogGroup); 138 msg.attr.nfa_len = sizeof(msg.attr) + sizeof(msg.cmd); 139 msg.attr.nfa_type = NFULA_CFG_CMD; 140 msg.cmd.command = NFULNL_CFG_CMD_UNBIND; 141 return send(makeSlice(msg)); 142 } 143 144 } // namespace 145 146 NFLogListener::NFLogListener(std::shared_ptr<NetlinkListenerInterface> listener) 147 : mListener(std::move(listener)) { 148 // Rx handler extracts nfgenmsg looks up and invokes registered dispatch function. 149 const auto rxHandler = [this](const nlmsghdr& nlmsg, const Slice msg) { 150 nfgenmsg nfmsg = {}; 151 extract(msg, nfmsg); 152 std::lock_guard<std::mutex> guard(mMutex); 153 const auto& fn = findWithDefault(mDispatchMap, ntohs(nfmsg.res_id), kDefaultDispatchFn); 154 fn(nlmsg, nfmsg, drop(msg, sizeof(nfmsg))); 155 }; 156 expectOk(mListener->subscribe(kNFLogPacketMsgType, rxHandler)); 157 158 // Each batch of NFLOG messages is terminated with NLMSG_DONE which is useless to us 159 const auto rxDoneHandler = [](const nlmsghdr&, const Slice msg) { 160 // Ignore NLMSG_DONE messages 161 nfgenmsg nfmsg = {}; 162 extract(msg, nfmsg); 163 // TODO: why is nfmsg filled with garbage? 164 }; 165 expectOk(mListener->subscribe(kNetlinkDoneMsgType, rxDoneHandler)); 166 } 167 168 NFLogListener::~NFLogListener() { 169 expectOk(mListener->unsubscribe(kNFLogPacketMsgType)); 170 expectOk(mListener->unsubscribe(kNetlinkDoneMsgType)); 171 const auto sendFn = [this](const Slice msg) { return mListener->send(msg); }; 172 for (auto pair : mDispatchMap) { 173 expectOk(cfgCmdUnbind(sendFn, pair.first)); 174 } 175 } 176 177 Status NFLogListener::subscribe(uint16_t nfLogGroup, const DispatchFn& fn) { 178 return subscribe(nfLogGroup, kDefaultPacketRange, fn); 179 } 180 181 Status NFLogListener::subscribe( 182 uint16_t nfLogGroup, uint32_t copyRange, const DispatchFn& fn) { 183 const auto sendFn = [this](const Slice msg) { return mListener->send(msg); }; 184 // Install fn into the dispatch map BEFORE requesting delivery of messages 185 { 186 std::lock_guard<std::mutex> guard(mMutex); 187 mDispatchMap[nfLogGroup] = fn; 188 } 189 RETURN_IF_NOT_OK(cfgCmdBind(sendFn, nfLogGroup)); 190 191 // Mode must be set for every nfLogGroup 192 const uint8_t copyMode = copyRange > 0 ? NFULNL_COPY_PACKET : NFULNL_COPY_NONE; 193 return cfgMode(sendFn, nfLogGroup, copyRange, copyMode); 194 } 195 196 Status NFLogListener::unsubscribe(uint16_t nfLogGroup) { 197 const auto sendFn = [this](const Slice msg) { return mListener->send(msg); }; 198 RETURN_IF_NOT_OK(cfgCmdUnbind(sendFn, nfLogGroup)); 199 // Remove from the dispatch map AFTER stopping message delivery. 200 { 201 std::lock_guard<std::mutex> guard(mMutex); 202 mDispatchMap.erase(nfLogGroup); 203 } 204 return ok; 205 } 206 207 StatusOr<std::unique_ptr<NFLogListener>> makeNFLogListener() { 208 const auto& sys = sSyscalls.get(); 209 ASSIGN_OR_RETURN(auto event, sys.eventfd(0, EFD_CLOEXEC)); 210 const auto domain = AF_NETLINK; 211 const auto flags = SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK; 212 const auto protocol = NETLINK_NETFILTER; 213 ASSIGN_OR_RETURN(auto sock, sys.socket(domain, flags, protocol)); 214 215 // Timestamps are disabled by default. Request RX timestamping 216 RETURN_IF_NOT_OK(sys.setsockopt<int32_t>(sock, SOL_SOCKET, SO_TIMESTAMP, 1)); 217 218 std::shared_ptr<NetlinkListenerInterface> listener = 219 std::make_unique<NetlinkListener>(std::move(event), std::move(sock)); 220 const auto sendFn = [&listener](const Slice msg) { return listener->send(msg); }; 221 RETURN_IF_NOT_OK(cfgCmdPfUnbind(sendFn)); 222 return std::unique_ptr<NFLogListener>(new NFLogListener(std::move(listener))); 223 } 224 225 } // namespace net 226 } // namespace android 227