WakeupController.cpp revision 08b84cd0d223ae3059ce7d4d55b389fdea187580
108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz/*
208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz * Copyright (C) 2017 The Android Open Source Project
308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz *
408b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz * Licensed under the Apache License, Version 2.0 (the "License");
508b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz * you may not use this file except in compliance with the License.
608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz * You may obtain a copy of the License at
708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz *
808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz *      http://www.apache.org/licenses/LICENSE-2.0
908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz *
1008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz * Unless required by applicable law or agreed to in writing, software
1108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz * distributed under the License is distributed on an "AS IS" BASIS,
1208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz * See the License for the specific language governing permissions and
1408b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz * limitations under the License.
1508b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz */
1608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
1708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#define LOG_TAG "WakeupController"
1808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
1908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include <endian.h>
2008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include <linux/netfilter/nfnetlink.h>
2108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include <linux/netfilter/nfnetlink_log.h>
2208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include <iostream>
2308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
2408b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include <android-base/stringprintf.h>
2508b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include <cutils/log.h>
2608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include <netdutils/Netfilter.h>
2708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include <netdutils/Netlink.h>
2808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
2908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include "IptablesRestoreController.h"
3008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include "NetlinkManager.h"
3108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include "WakeupController.h"
3208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
3308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelznamespace android {
3408b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelznamespace net {
3508b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
3608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelzusing base::StringPrintf;
3708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelzusing netdutils::Slice;
3808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelzusing netdutils::Status;
3908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
4008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelzconst char WakeupController::LOCAL_MANGLE_INPUT[] = "wakeupctrl_mangle_INPUT";
4108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
4208b84cd0d223ae3059ce7d4d55b389fdea187580Joel ScherpelzWakeupController::~WakeupController() {
4308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    expectOk(mListener->unsubscribe(NetlinkManager::NFLOG_WAKEUP_GROUP));
4408b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz}
4508b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
4608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelznetdutils::Status WakeupController::init(NFLogListenerInterface* listener) {
4708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    mListener = listener;
4808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    const auto msgHandler = [this](const nlmsghdr&, const nfgenmsg&, const Slice msg) {
4908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        std::string prefix;
5008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        uid_t uid = -1;
5108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        gid_t gid = -1;
5208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        uint64_t timestampNs = -1;
5308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        const auto attrHandler = [&prefix, &uid, &gid, &timestampNs](const nlattr attr,
5408b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                                                                     const Slice payload) {
5508b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz            switch (attr.nla_type) {
5608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                case NFULA_TIMESTAMP: {
5708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    timespec timespec = {};
5808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    extract(payload, timespec);
5908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    constexpr uint64_t kNsPerS = 1000000000ULL;
6008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    timestampNs = be32toh(timespec.tv_nsec) + (be32toh(timespec.tv_sec) * kNsPerS);
6108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    break;
6208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                }
6308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                case NFULA_PREFIX:
6408b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    // Strip trailing '\0'
6508b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    prefix = toString(take(payload, payload.size() - 1));
6608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    break;
6708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                case NFULA_UID:
6808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    extract(payload, uid);
6908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    uid = be32toh(uid);
7008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    break;
7108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                case NFULA_GID:
7208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    extract(payload, gid);
7308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    gid = be32toh(gid);
7408b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    break;
7508b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                default:
7608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    break;
7708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz            }
7808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        };
7908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        forEachNetlinkAttribute(msg, attrHandler);
8008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        mReport(prefix, uid, gid, timestampNs);
8108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    };
8208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    return mListener->subscribe(NetlinkManager::NFLOG_WAKEUP_GROUP, msgHandler);
8308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz}
8408b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
8508b84cd0d223ae3059ce7d4d55b389fdea187580Joel ScherpelzStatus WakeupController::addInterface(const std::string& ifName, const std::string& prefix,
8608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                                    uint32_t mark, uint32_t mask) {
8708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    return execIptables("-A", ifName, prefix, mark, mask);
8808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz}
8908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
9008b84cd0d223ae3059ce7d4d55b389fdea187580Joel ScherpelzStatus WakeupController::delInterface(const std::string& ifName, const std::string& prefix,
9108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                                    uint32_t mark, uint32_t mask) {
9208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    return execIptables("-D", ifName, prefix, mark, mask);
9308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz}
9408b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
9508b84cd0d223ae3059ce7d4d55b389fdea187580Joel ScherpelzStatus WakeupController::execIptables(const std::string& action, const std::string& ifName,
9608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                                      const std::string& prefix, uint32_t mark, uint32_t mask) {
9708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    // NFLOG messages to batch before releasing to userspace
9808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    constexpr int kBatch = 8;
9908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    // Max log message rate in packets/second
10008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    constexpr int kRateLimit = 10;
10108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    const char kFormat[] =
10208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        "*mangle\n%s %s -i %s -j NFLOG --nflog-prefix %s --nflog-group %d --nflog-threshold %d"
10308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        " -m mark --mark 0x%08x/0x%08x -m limit --limit %d/s\nCOMMIT\n";
10408b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    const auto cmd = StringPrintf(
10508b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        kFormat, action.c_str(), WakeupController::LOCAL_MANGLE_INPUT, ifName.c_str(),
10608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        prefix.c_str(), NetlinkManager::NFLOG_WAKEUP_GROUP, kBatch, mark, mask, kRateLimit);
10708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
10808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    std::string out;
10908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    auto rv = mIptables->execute(V4V6, cmd, &out);
11008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    if (rv != 0) {
11108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        auto s = Status(rv, "Failed to execute iptables cmd: " + cmd + ", out: " + out);
11208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        ALOGE("%s", toString(s).c_str());
11308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        return s;
11408b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    }
11508b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    return netdutils::status::ok;
11608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz}
11708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
11808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz}  // namespace net
11908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz}  // namespace android
120