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
19e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi#include <arpa/inet.h>
20e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi#include <iostream>
2108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include <linux/netfilter/nfnetlink.h>
2208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include <linux/netfilter/nfnetlink_log.h>
23e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi#include <sys/socket.h>
24e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi#include <netinet/if_ether.h>
25e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi#include <netinet/in.h>
26e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi#include <netinet/ip.h>
27e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi#include <netinet/ip6.h>
28e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi#include <netinet/tcp.h>
29e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi#include <netinet/udp.h>
3008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
31e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi#include <android-base/strings.h>
3208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include <android-base/stringprintf.h>
3308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include <cutils/log.h>
3408b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include <netdutils/Netfilter.h>
3508b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include <netdutils/Netlink.h>
3608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
3708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include "IptablesRestoreController.h"
3808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include "NetlinkManager.h"
3908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz#include "WakeupController.h"
4008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
4108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelznamespace android {
4208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelznamespace net {
4308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
4408b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelzusing base::StringPrintf;
4508b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelzusing netdutils::Slice;
4608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelzusing netdutils::Status;
4708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
4808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelzconst char WakeupController::LOCAL_MANGLE_INPUT[] = "wakeupctrl_mangle_INPUT";
4908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
50e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichiconst uint32_t WakeupController::kDefaultPacketCopyRange =
51e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        sizeof(struct tcphdr) + sizeof(struct ip6_hdr);
52e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi
53e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichistatic void extractIpPorts(WakeupController::ReportArgs& args, Slice payload) {
54e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi    switch (args.ipNextHeader) {
55e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        case IPPROTO_TCP: {
56e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            struct tcphdr header;
57e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            if (extract(payload, header) < sizeof(struct tcphdr)) {
58e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                return;
59e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            }
60e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            args.srcPort = ntohs(header.th_sport);
61e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            args.dstPort = ntohs(header.th_dport);
62e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            break;
63e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        }
64e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        case IPPROTO_UDP: {
65e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            struct udphdr header;
66e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            if (extract(payload, header) < sizeof(struct udphdr)) {
67e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                return;
68e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            }
69e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            args.srcPort = ntohs(header.uh_sport);
70e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            args.dstPort = ntohs(header.uh_dport);
71e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            break;
72e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        }
73e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        default:
74e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            break;
75e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi    }
76e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi}
77e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi
78e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichistatic void extractIpHeader(WakeupController::ReportArgs& args, Slice payload) {
79e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi    switch (args.ethertype) {
80e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        case ETH_P_IP: {
81e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            struct iphdr header;
82e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            if (extract(payload, header) < sizeof(struct iphdr)) {
83e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                return;
84e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            }
85e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            args.ipNextHeader = header.protocol;
86e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            char addr[INET_ADDRSTRLEN] = {};
87e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            inet_ntop(AF_INET, &header.saddr, addr, sizeof(addr));
88e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            args.srcIp = addr;
89e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            inet_ntop(AF_INET, &header.daddr, addr, sizeof(addr));
90e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            args.dstIp = addr;
91e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            extractIpPorts(args, drop(payload, header.ihl * 4)); // ipv4 IHL counts 32 bit words.
92e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            break;
93e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        }
94e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        case ETH_P_IPV6: {
95e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            struct ip6_hdr header;
96e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            if (extract(payload, header) < sizeof(struct ip6_hdr)) {
97e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                return;
98e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            }
99e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            args.ipNextHeader = header.ip6_nxt;
100e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            char addr[INET6_ADDRSTRLEN] = {};
101e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            inet_ntop(AF_INET6, &header.ip6_src, addr, sizeof(addr));
102e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            args.srcIp = addr;
103e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            inet_ntop(AF_INET6, &header.ip6_dst, addr, sizeof(addr));
104e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            args.dstIp = addr;
105e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            // TODO: also deal with extension headers
106e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            if (args.ipNextHeader == IPPROTO_TCP || args.ipNextHeader == IPPROTO_UDP) {
107e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                extractIpPorts(args, drop(payload, sizeof(header)));
108e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            }
109e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            break;
110e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        }
111e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        default:
112e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            break;
113e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi    }
114e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi}
115e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi
11608b84cd0d223ae3059ce7d4d55b389fdea187580Joel ScherpelzWakeupController::~WakeupController() {
11708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    expectOk(mListener->unsubscribe(NetlinkManager::NFLOG_WAKEUP_GROUP));
11808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz}
11908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
12008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelznetdutils::Status WakeupController::init(NFLogListenerInterface* listener) {
12108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    mListener = listener;
12208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    const auto msgHandler = [this](const nlmsghdr&, const nfgenmsg&, const Slice msg) {
123e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi
124e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        struct WakeupController::ReportArgs args = {
125e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            .uid = -1,
126e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            .gid = -1,
127e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            .ethertype = -1,
128e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            .ipNextHeader = -1,
129e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            .srcPort = -1,
130e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            .dstPort = -1,
131e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            // and all other fields set to 0 as the default
132e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        };
133e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        bool parseAgain = false;
134e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi
135e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        const auto attrHandler = [&args, &parseAgain](const nlattr attr, const Slice payload) {
13608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz            switch (attr.nla_type) {
13708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                case NFULA_TIMESTAMP: {
1385a73b949b859cff86b838c0fd467894ee88820f9Hugo Benichi                    timespec ts = {};
1395a73b949b859cff86b838c0fd467894ee88820f9Hugo Benichi                    extract(payload, ts);
14008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    constexpr uint64_t kNsPerS = 1000000000ULL;
141e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    args.timestampNs = ntohl(ts.tv_nsec) + (ntohl(ts.tv_sec) * kNsPerS);
14208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    break;
14308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                }
14408b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                case NFULA_PREFIX:
14508b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    // Strip trailing '\0'
146e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    args.prefix = toString(take(payload, payload.size() - 1));
14708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    break;
14808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                case NFULA_UID:
149e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    extract(payload, args.uid);
150e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    args.uid = ntohl(args.uid);
15108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    break;
15208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                case NFULA_GID:
153e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    extract(payload, args.gid);
154e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    args.gid = ntohl(args.gid);
155e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    break;
156e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                case NFULA_HWADDR: {
157e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    struct nfulnl_msg_packet_hw hwaddr = {};
158e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    extract(payload, hwaddr);
159e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    size_t hwAddrLen = ntohs(hwaddr.hw_addrlen);
160e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    hwAddrLen = std::min(hwAddrLen, sizeof(hwaddr.hw_addr));
161e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    args.dstHw.assign(hwaddr.hw_addr, hwaddr.hw_addr + hwAddrLen);
162e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    break;
163e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                }
164e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                case NFULA_PACKET_HDR: {
165e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    struct nfulnl_msg_packet_hdr packetHdr = {};
166e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    extract(payload, packetHdr);
167e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    args.ethertype = ntohs(packetHdr.hw_protocol);
168e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    break;
169e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                }
170e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                case NFULA_PAYLOAD:
171e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    // The packet payload is expected to come last in the Netlink message.
172e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    // At that point NFULA_PACKET_HDR has already been parsed and processed.
173e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    // If this is not the case, set parseAgain to true.
174e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    parseAgain = (args.ethertype == -1);
175e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi                    extractIpHeader(args, payload);
17608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    break;
17708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                default:
17808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                    break;
17908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz            }
18008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        };
181e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi
18208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        forEachNetlinkAttribute(msg, attrHandler);
183e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        if (parseAgain) {
184e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            // NFULA_PAYLOAD was parsed before NFULA_PACKET_HDR.
185e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            // Now that the ethertype is known, reparse msg for correctly extracting the payload.
186e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            forEachNetlinkAttribute(msg, attrHandler);
187e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        }
188e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi        mReport(args);
18908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    };
190e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi    return mListener->subscribe(NetlinkManager::NFLOG_WAKEUP_GROUP,
191e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            WakeupController::kDefaultPacketCopyRange, msgHandler);
19208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz}
19308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
19408b84cd0d223ae3059ce7d4d55b389fdea187580Joel ScherpelzStatus WakeupController::addInterface(const std::string& ifName, const std::string& prefix,
19508b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                                    uint32_t mark, uint32_t mask) {
19608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    return execIptables("-A", ifName, prefix, mark, mask);
19708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz}
19808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
19908b84cd0d223ae3059ce7d4d55b389fdea187580Joel ScherpelzStatus WakeupController::delInterface(const std::string& ifName, const std::string& prefix,
20008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                                    uint32_t mark, uint32_t mask) {
20108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    return execIptables("-D", ifName, prefix, mark, mask);
20208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz}
20308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
20408b84cd0d223ae3059ce7d4d55b389fdea187580Joel ScherpelzStatus WakeupController::execIptables(const std::string& action, const std::string& ifName,
20508b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz                                      const std::string& prefix, uint32_t mark, uint32_t mask) {
20608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    // NFLOG messages to batch before releasing to userspace
20708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    constexpr int kBatch = 8;
20808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    // Max log message rate in packets/second
20908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    constexpr int kRateLimit = 10;
21008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    const char kFormat[] =
21108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        "*mangle\n%s %s -i %s -j NFLOG --nflog-prefix %s --nflog-group %d --nflog-threshold %d"
21277660392eb3e9aa287cc02307c443ee64b5fc570Hugo Benichi        " -m mark --mark 0x%08x/0x%08x -m limit --limit %d/s\nCOMMIT\n";
21308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    const auto cmd = StringPrintf(
214e874b7f00ce5bd34a750ed1eb021f50679c6535dHugo Benichi            kFormat, action.c_str(), WakeupController::LOCAL_MANGLE_INPUT, ifName.c_str(),
21577660392eb3e9aa287cc02307c443ee64b5fc570Hugo Benichi            prefix.c_str(), NetlinkManager::NFLOG_WAKEUP_GROUP, kBatch, mark, mask, kRateLimit);
21608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
21708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    std::string out;
21808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    auto rv = mIptables->execute(V4V6, cmd, &out);
21908b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    if (rv != 0) {
22008b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        auto s = Status(rv, "Failed to execute iptables cmd: " + cmd + ", out: " + out);
22108b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        ALOGE("%s", toString(s).c_str());
22208b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz        return s;
22308b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    }
22408b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz    return netdutils::status::ok;
22508b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz}
22608b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz
22708b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz}  // namespace net
22808b84cd0d223ae3059ce7d4d55b389fdea187580Joel Scherpelz}  // namespace android
229