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 "WakeupController" 18 19 #include <endian.h> 20 #include <linux/netfilter/nfnetlink.h> 21 #include <linux/netfilter/nfnetlink_log.h> 22 #include <iostream> 23 24 #include <android-base/stringprintf.h> 25 #include <cutils/log.h> 26 #include <netdutils/Netfilter.h> 27 #include <netdutils/Netlink.h> 28 29 #include "IptablesRestoreController.h" 30 #include "NetlinkManager.h" 31 #include "WakeupController.h" 32 33 namespace android { 34 namespace net { 35 36 using base::StringPrintf; 37 using netdutils::Slice; 38 using netdutils::Status; 39 40 const char WakeupController::LOCAL_MANGLE_INPUT[] = "wakeupctrl_mangle_INPUT"; 41 42 WakeupController::~WakeupController() { 43 expectOk(mListener->unsubscribe(NetlinkManager::NFLOG_WAKEUP_GROUP)); 44 } 45 46 netdutils::Status WakeupController::init(NFLogListenerInterface* listener) { 47 mListener = listener; 48 const auto msgHandler = [this](const nlmsghdr&, const nfgenmsg&, const Slice msg) { 49 std::string prefix; 50 uid_t uid = -1; 51 gid_t gid = -1; 52 uint64_t timestampNs = -1; 53 const auto attrHandler = [&prefix, &uid, &gid, ×tampNs](const nlattr attr, 54 const Slice payload) { 55 switch (attr.nla_type) { 56 case NFULA_TIMESTAMP: { 57 timespec timespec = {}; 58 extract(payload, timespec); 59 constexpr uint64_t kNsPerS = 1000000000ULL; 60 timestampNs = be32toh(timespec.tv_nsec) + (be32toh(timespec.tv_sec) * kNsPerS); 61 break; 62 } 63 case NFULA_PREFIX: 64 // Strip trailing '\0' 65 prefix = toString(take(payload, payload.size() - 1)); 66 break; 67 case NFULA_UID: 68 extract(payload, uid); 69 uid = be32toh(uid); 70 break; 71 case NFULA_GID: 72 extract(payload, gid); 73 gid = be32toh(gid); 74 break; 75 default: 76 break; 77 } 78 }; 79 forEachNetlinkAttribute(msg, attrHandler); 80 mReport(prefix, uid, gid, timestampNs); 81 }; 82 return mListener->subscribe(NetlinkManager::NFLOG_WAKEUP_GROUP, msgHandler); 83 } 84 85 Status WakeupController::addInterface(const std::string& ifName, const std::string& prefix, 86 uint32_t mark, uint32_t mask) { 87 return execIptables("-A", ifName, prefix, mark, mask); 88 } 89 90 Status WakeupController::delInterface(const std::string& ifName, const std::string& prefix, 91 uint32_t mark, uint32_t mask) { 92 return execIptables("-D", ifName, prefix, mark, mask); 93 } 94 95 Status WakeupController::execIptables(const std::string& action, const std::string& ifName, 96 const std::string& prefix, uint32_t mark, uint32_t mask) { 97 // NFLOG messages to batch before releasing to userspace 98 constexpr int kBatch = 8; 99 // Max log message rate in packets/second 100 constexpr int kRateLimit = 10; 101 const char kFormat[] = 102 "*mangle\n%s %s -i %s -j NFLOG --nflog-prefix %s --nflog-group %d --nflog-threshold %d" 103 " -m mark --mark 0x%08x/0x%08x -m limit --limit %d/s\nCOMMIT\n"; 104 const auto cmd = StringPrintf( 105 kFormat, action.c_str(), WakeupController::LOCAL_MANGLE_INPUT, ifName.c_str(), 106 prefix.c_str(), NetlinkManager::NFLOG_WAKEUP_GROUP, kBatch, mark, mask, kRateLimit); 107 108 std::string out; 109 auto rv = mIptables->execute(V4V6, cmd, &out); 110 if (rv != 0) { 111 auto s = Status(rv, "Failed to execute iptables cmd: " + cmd + ", out: " + out); 112 ALOGE("%s", toString(s).c_str()); 113 return s; 114 } 115 return netdutils::status::ok; 116 } 117 118 } // namespace net 119 } // namespace android 120