1*8542734aSAndroid Build Coastguard Worker /*
2*8542734aSAndroid Build Coastguard Worker * Copyright (C) 2017 The Android Open Source Project
3*8542734aSAndroid Build Coastguard Worker *
4*8542734aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*8542734aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*8542734aSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*8542734aSAndroid Build Coastguard Worker *
8*8542734aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*8542734aSAndroid Build Coastguard Worker *
10*8542734aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*8542734aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*8542734aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*8542734aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*8542734aSAndroid Build Coastguard Worker * limitations under the License.
15*8542734aSAndroid Build Coastguard Worker */
16*8542734aSAndroid Build Coastguard Worker
17*8542734aSAndroid Build Coastguard Worker #define LOG_TAG "WakeupController"
18*8542734aSAndroid Build Coastguard Worker
19*8542734aSAndroid Build Coastguard Worker #include <arpa/inet.h>
20*8542734aSAndroid Build Coastguard Worker #include <iostream>
21*8542734aSAndroid Build Coastguard Worker #include <linux/netfilter/nfnetlink.h>
22*8542734aSAndroid Build Coastguard Worker #include <linux/netfilter/nfnetlink_log.h>
23*8542734aSAndroid Build Coastguard Worker #include <sys/socket.h>
24*8542734aSAndroid Build Coastguard Worker #include <netinet/if_ether.h>
25*8542734aSAndroid Build Coastguard Worker #include <netinet/in.h>
26*8542734aSAndroid Build Coastguard Worker #include <netinet/ip.h>
27*8542734aSAndroid Build Coastguard Worker #include <netinet/ip6.h>
28*8542734aSAndroid Build Coastguard Worker #include <netinet/tcp.h>
29*8542734aSAndroid Build Coastguard Worker #include <netinet/udp.h>
30*8542734aSAndroid Build Coastguard Worker
31*8542734aSAndroid Build Coastguard Worker #include <android-base/strings.h>
32*8542734aSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
33*8542734aSAndroid Build Coastguard Worker #include <log/log.h>
34*8542734aSAndroid Build Coastguard Worker #include <netdutils/Netfilter.h>
35*8542734aSAndroid Build Coastguard Worker #include <netdutils/Netlink.h>
36*8542734aSAndroid Build Coastguard Worker
37*8542734aSAndroid Build Coastguard Worker #include "IptablesRestoreController.h"
38*8542734aSAndroid Build Coastguard Worker #include "NetlinkManager.h"
39*8542734aSAndroid Build Coastguard Worker #include "WakeupController.h"
40*8542734aSAndroid Build Coastguard Worker
41*8542734aSAndroid Build Coastguard Worker namespace android {
42*8542734aSAndroid Build Coastguard Worker namespace net {
43*8542734aSAndroid Build Coastguard Worker
44*8542734aSAndroid Build Coastguard Worker using base::StringPrintf;
45*8542734aSAndroid Build Coastguard Worker using netdutils::Slice;
46*8542734aSAndroid Build Coastguard Worker using netdutils::Status;
47*8542734aSAndroid Build Coastguard Worker
48*8542734aSAndroid Build Coastguard Worker const char WakeupController::LOCAL_MANGLE_INPUT[] = "wakeupctrl_mangle_INPUT";
49*8542734aSAndroid Build Coastguard Worker
50*8542734aSAndroid Build Coastguard Worker const uint32_t WakeupController::kDefaultPacketCopyRange =
51*8542734aSAndroid Build Coastguard Worker sizeof(struct tcphdr) + sizeof(struct ip6_hdr);
52*8542734aSAndroid Build Coastguard Worker
extractIpPorts(WakeupController::ReportArgs & args,Slice payload)53*8542734aSAndroid Build Coastguard Worker static void extractIpPorts(WakeupController::ReportArgs& args, Slice payload) {
54*8542734aSAndroid Build Coastguard Worker switch (args.ipNextHeader) {
55*8542734aSAndroid Build Coastguard Worker case IPPROTO_TCP: {
56*8542734aSAndroid Build Coastguard Worker struct tcphdr header;
57*8542734aSAndroid Build Coastguard Worker if (extract(payload, header) < sizeof(struct tcphdr)) {
58*8542734aSAndroid Build Coastguard Worker return;
59*8542734aSAndroid Build Coastguard Worker }
60*8542734aSAndroid Build Coastguard Worker args.srcPort = ntohs(header.th_sport);
61*8542734aSAndroid Build Coastguard Worker args.dstPort = ntohs(header.th_dport);
62*8542734aSAndroid Build Coastguard Worker break;
63*8542734aSAndroid Build Coastguard Worker }
64*8542734aSAndroid Build Coastguard Worker case IPPROTO_UDP: {
65*8542734aSAndroid Build Coastguard Worker struct udphdr header;
66*8542734aSAndroid Build Coastguard Worker if (extract(payload, header) < sizeof(struct udphdr)) {
67*8542734aSAndroid Build Coastguard Worker return;
68*8542734aSAndroid Build Coastguard Worker }
69*8542734aSAndroid Build Coastguard Worker args.srcPort = ntohs(header.uh_sport);
70*8542734aSAndroid Build Coastguard Worker args.dstPort = ntohs(header.uh_dport);
71*8542734aSAndroid Build Coastguard Worker break;
72*8542734aSAndroid Build Coastguard Worker }
73*8542734aSAndroid Build Coastguard Worker default:
74*8542734aSAndroid Build Coastguard Worker break;
75*8542734aSAndroid Build Coastguard Worker }
76*8542734aSAndroid Build Coastguard Worker }
77*8542734aSAndroid Build Coastguard Worker
extractIpHeader(WakeupController::ReportArgs & args,Slice payload)78*8542734aSAndroid Build Coastguard Worker static void extractIpHeader(WakeupController::ReportArgs& args, Slice payload) {
79*8542734aSAndroid Build Coastguard Worker switch (args.ethertype) {
80*8542734aSAndroid Build Coastguard Worker case ETH_P_IP: {
81*8542734aSAndroid Build Coastguard Worker struct iphdr header;
82*8542734aSAndroid Build Coastguard Worker if (extract(payload, header) < sizeof(struct iphdr)) {
83*8542734aSAndroid Build Coastguard Worker return;
84*8542734aSAndroid Build Coastguard Worker }
85*8542734aSAndroid Build Coastguard Worker args.ipNextHeader = header.protocol;
86*8542734aSAndroid Build Coastguard Worker char addr[INET_ADDRSTRLEN] = {};
87*8542734aSAndroid Build Coastguard Worker inet_ntop(AF_INET, &header.saddr, addr, sizeof(addr));
88*8542734aSAndroid Build Coastguard Worker args.srcIp = addr;
89*8542734aSAndroid Build Coastguard Worker inet_ntop(AF_INET, &header.daddr, addr, sizeof(addr));
90*8542734aSAndroid Build Coastguard Worker args.dstIp = addr;
91*8542734aSAndroid Build Coastguard Worker extractIpPorts(args, drop(payload, header.ihl * 4)); // ipv4 IHL counts 32 bit words.
92*8542734aSAndroid Build Coastguard Worker break;
93*8542734aSAndroid Build Coastguard Worker }
94*8542734aSAndroid Build Coastguard Worker case ETH_P_IPV6: {
95*8542734aSAndroid Build Coastguard Worker struct ip6_hdr header;
96*8542734aSAndroid Build Coastguard Worker if (extract(payload, header) < sizeof(struct ip6_hdr)) {
97*8542734aSAndroid Build Coastguard Worker return;
98*8542734aSAndroid Build Coastguard Worker }
99*8542734aSAndroid Build Coastguard Worker args.ipNextHeader = header.ip6_nxt;
100*8542734aSAndroid Build Coastguard Worker char addr[INET6_ADDRSTRLEN] = {};
101*8542734aSAndroid Build Coastguard Worker inet_ntop(AF_INET6, &header.ip6_src, addr, sizeof(addr));
102*8542734aSAndroid Build Coastguard Worker args.srcIp = addr;
103*8542734aSAndroid Build Coastguard Worker inet_ntop(AF_INET6, &header.ip6_dst, addr, sizeof(addr));
104*8542734aSAndroid Build Coastguard Worker args.dstIp = addr;
105*8542734aSAndroid Build Coastguard Worker // TODO: also deal with extension headers
106*8542734aSAndroid Build Coastguard Worker if (args.ipNextHeader == IPPROTO_TCP || args.ipNextHeader == IPPROTO_UDP) {
107*8542734aSAndroid Build Coastguard Worker extractIpPorts(args, drop(payload, sizeof(header)));
108*8542734aSAndroid Build Coastguard Worker }
109*8542734aSAndroid Build Coastguard Worker break;
110*8542734aSAndroid Build Coastguard Worker }
111*8542734aSAndroid Build Coastguard Worker default:
112*8542734aSAndroid Build Coastguard Worker break;
113*8542734aSAndroid Build Coastguard Worker }
114*8542734aSAndroid Build Coastguard Worker }
115*8542734aSAndroid Build Coastguard Worker
~WakeupController()116*8542734aSAndroid Build Coastguard Worker WakeupController::~WakeupController() {
117*8542734aSAndroid Build Coastguard Worker expectOk(mListener->unsubscribe(NetlinkManager::NFLOG_WAKEUP_GROUP));
118*8542734aSAndroid Build Coastguard Worker }
119*8542734aSAndroid Build Coastguard Worker
init(NFLogListenerInterface * listener)120*8542734aSAndroid Build Coastguard Worker netdutils::Status WakeupController::init(NFLogListenerInterface* listener) {
121*8542734aSAndroid Build Coastguard Worker mListener = listener;
122*8542734aSAndroid Build Coastguard Worker const auto msgHandler = [this](const nlmsghdr&, const nfgenmsg&, const Slice msg) {
123*8542734aSAndroid Build Coastguard Worker
124*8542734aSAndroid Build Coastguard Worker struct WakeupController::ReportArgs args = {
125*8542734aSAndroid Build Coastguard Worker .uid = -1,
126*8542734aSAndroid Build Coastguard Worker .gid = -1,
127*8542734aSAndroid Build Coastguard Worker .ethertype = -1,
128*8542734aSAndroid Build Coastguard Worker .ipNextHeader = -1,
129*8542734aSAndroid Build Coastguard Worker .srcPort = -1,
130*8542734aSAndroid Build Coastguard Worker .dstPort = -1,
131*8542734aSAndroid Build Coastguard Worker // and all other fields set to 0 as the default
132*8542734aSAndroid Build Coastguard Worker };
133*8542734aSAndroid Build Coastguard Worker bool parseAgain = false;
134*8542734aSAndroid Build Coastguard Worker
135*8542734aSAndroid Build Coastguard Worker const auto attrHandler = [&args, &parseAgain](const nlattr attr, const Slice payload) {
136*8542734aSAndroid Build Coastguard Worker switch (attr.nla_type) {
137*8542734aSAndroid Build Coastguard Worker case NFULA_TIMESTAMP: {
138*8542734aSAndroid Build Coastguard Worker timespec ts = {};
139*8542734aSAndroid Build Coastguard Worker extract(payload, ts);
140*8542734aSAndroid Build Coastguard Worker constexpr uint64_t kNsPerS = 1000000000ULL;
141*8542734aSAndroid Build Coastguard Worker args.timestampNs = ntohl(ts.tv_nsec) + (ntohl(ts.tv_sec) * kNsPerS);
142*8542734aSAndroid Build Coastguard Worker break;
143*8542734aSAndroid Build Coastguard Worker }
144*8542734aSAndroid Build Coastguard Worker case NFULA_PREFIX:
145*8542734aSAndroid Build Coastguard Worker // Strip trailing '\0'
146*8542734aSAndroid Build Coastguard Worker args.prefix = toString(take(payload, payload.size() - 1));
147*8542734aSAndroid Build Coastguard Worker break;
148*8542734aSAndroid Build Coastguard Worker case NFULA_UID:
149*8542734aSAndroid Build Coastguard Worker extract(payload, args.uid);
150*8542734aSAndroid Build Coastguard Worker args.uid = ntohl(args.uid);
151*8542734aSAndroid Build Coastguard Worker break;
152*8542734aSAndroid Build Coastguard Worker case NFULA_GID:
153*8542734aSAndroid Build Coastguard Worker extract(payload, args.gid);
154*8542734aSAndroid Build Coastguard Worker args.gid = ntohl(args.gid);
155*8542734aSAndroid Build Coastguard Worker break;
156*8542734aSAndroid Build Coastguard Worker case NFULA_HWADDR: {
157*8542734aSAndroid Build Coastguard Worker struct nfulnl_msg_packet_hw hwaddr = {};
158*8542734aSAndroid Build Coastguard Worker extract(payload, hwaddr);
159*8542734aSAndroid Build Coastguard Worker size_t hwAddrLen = ntohs(hwaddr.hw_addrlen);
160*8542734aSAndroid Build Coastguard Worker hwAddrLen = std::min(hwAddrLen, sizeof(hwaddr.hw_addr));
161*8542734aSAndroid Build Coastguard Worker args.dstHw.assign(hwaddr.hw_addr, hwaddr.hw_addr + hwAddrLen);
162*8542734aSAndroid Build Coastguard Worker break;
163*8542734aSAndroid Build Coastguard Worker }
164*8542734aSAndroid Build Coastguard Worker case NFULA_PACKET_HDR: {
165*8542734aSAndroid Build Coastguard Worker struct nfulnl_msg_packet_hdr packetHdr = {};
166*8542734aSAndroid Build Coastguard Worker extract(payload, packetHdr);
167*8542734aSAndroid Build Coastguard Worker args.ethertype = ntohs(packetHdr.hw_protocol);
168*8542734aSAndroid Build Coastguard Worker break;
169*8542734aSAndroid Build Coastguard Worker }
170*8542734aSAndroid Build Coastguard Worker case NFULA_PAYLOAD:
171*8542734aSAndroid Build Coastguard Worker // The packet payload is expected to come last in the Netlink message.
172*8542734aSAndroid Build Coastguard Worker // At that point NFULA_PACKET_HDR has already been parsed and processed.
173*8542734aSAndroid Build Coastguard Worker // If this is not the case, set parseAgain to true.
174*8542734aSAndroid Build Coastguard Worker parseAgain = (args.ethertype == -1);
175*8542734aSAndroid Build Coastguard Worker extractIpHeader(args, payload);
176*8542734aSAndroid Build Coastguard Worker break;
177*8542734aSAndroid Build Coastguard Worker default:
178*8542734aSAndroid Build Coastguard Worker break;
179*8542734aSAndroid Build Coastguard Worker }
180*8542734aSAndroid Build Coastguard Worker };
181*8542734aSAndroid Build Coastguard Worker
182*8542734aSAndroid Build Coastguard Worker forEachNetlinkAttribute(msg, attrHandler);
183*8542734aSAndroid Build Coastguard Worker if (parseAgain) {
184*8542734aSAndroid Build Coastguard Worker // NFULA_PAYLOAD was parsed before NFULA_PACKET_HDR.
185*8542734aSAndroid Build Coastguard Worker // Now that the ethertype is known, reparse msg for correctly extracting the payload.
186*8542734aSAndroid Build Coastguard Worker forEachNetlinkAttribute(msg, attrHandler);
187*8542734aSAndroid Build Coastguard Worker }
188*8542734aSAndroid Build Coastguard Worker mReport(args);
189*8542734aSAndroid Build Coastguard Worker };
190*8542734aSAndroid Build Coastguard Worker return mListener->subscribe(NetlinkManager::NFLOG_WAKEUP_GROUP,
191*8542734aSAndroid Build Coastguard Worker WakeupController::kDefaultPacketCopyRange, msgHandler);
192*8542734aSAndroid Build Coastguard Worker }
193*8542734aSAndroid Build Coastguard Worker
addInterface(const std::string & ifName,const std::string & prefix,uint32_t mark,uint32_t mask)194*8542734aSAndroid Build Coastguard Worker Status WakeupController::addInterface(const std::string& ifName, const std::string& prefix,
195*8542734aSAndroid Build Coastguard Worker uint32_t mark, uint32_t mask) {
196*8542734aSAndroid Build Coastguard Worker return execIptables("-A", ifName, prefix, mark, mask);
197*8542734aSAndroid Build Coastguard Worker }
198*8542734aSAndroid Build Coastguard Worker
delInterface(const std::string & ifName,const std::string & prefix,uint32_t mark,uint32_t mask)199*8542734aSAndroid Build Coastguard Worker Status WakeupController::delInterface(const std::string& ifName, const std::string& prefix,
200*8542734aSAndroid Build Coastguard Worker uint32_t mark, uint32_t mask) {
201*8542734aSAndroid Build Coastguard Worker return execIptables("-D", ifName, prefix, mark, mask);
202*8542734aSAndroid Build Coastguard Worker }
203*8542734aSAndroid Build Coastguard Worker
execIptables(const std::string & action,const std::string & ifName,const std::string & prefix,uint32_t mark,uint32_t mask)204*8542734aSAndroid Build Coastguard Worker Status WakeupController::execIptables(const std::string& action, const std::string& ifName,
205*8542734aSAndroid Build Coastguard Worker const std::string& prefix, uint32_t mark, uint32_t mask) {
206*8542734aSAndroid Build Coastguard Worker // NFLOG messages to batch before releasing to userspace
207*8542734aSAndroid Build Coastguard Worker constexpr int kBatch = 8;
208*8542734aSAndroid Build Coastguard Worker const char kFormat[] =
209*8542734aSAndroid Build Coastguard Worker "*mangle\n"
210*8542734aSAndroid Build Coastguard Worker "%s %s -i %s -m mark --mark 0x%08x/0x%08x -m limit --limit 10/s"
211*8542734aSAndroid Build Coastguard Worker " -j NFLOG --nflog-prefix %s --nflog-group %d --nflog-threshold %d\n"
212*8542734aSAndroid Build Coastguard Worker "COMMIT\n";
213*8542734aSAndroid Build Coastguard Worker const auto cmd = StringPrintf(kFormat,
214*8542734aSAndroid Build Coastguard Worker action.c_str(), WakeupController::LOCAL_MANGLE_INPUT, ifName.c_str(), mark, mask,
215*8542734aSAndroid Build Coastguard Worker prefix.c_str(), NetlinkManager::NFLOG_WAKEUP_GROUP, kBatch);
216*8542734aSAndroid Build Coastguard Worker
217*8542734aSAndroid Build Coastguard Worker std::string out;
218*8542734aSAndroid Build Coastguard Worker auto rv = mIptables->execute(V4V6, cmd, &out);
219*8542734aSAndroid Build Coastguard Worker if (rv != 0) {
220*8542734aSAndroid Build Coastguard Worker auto s = Status(rv, "Failed to execute iptables cmd: " + cmd + ", out: " + out);
221*8542734aSAndroid Build Coastguard Worker ALOGE("%s", toString(s).c_str());
222*8542734aSAndroid Build Coastguard Worker return s;
223*8542734aSAndroid Build Coastguard Worker }
224*8542734aSAndroid Build Coastguard Worker return netdutils::status::ok;
225*8542734aSAndroid Build Coastguard Worker }
226*8542734aSAndroid Build Coastguard Worker
227*8542734aSAndroid Build Coastguard Worker } // namespace net
228*8542734aSAndroid Build Coastguard Worker } // namespace android
229