1 /*
2  * Copyright (C) 2012 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 /*
18  * MODUS OPERANDI
19  * --------------
20  *
21  * IPTABLES command sequence:
22  *
23  * iptables -F
24  *
25  * iptables -t raw -F idletimer_PREROUTING
26  * iptables -t mangle -F idletimer_POSTROUTING
27  *
28  *
29  * iptables -t raw -N idletimer_PREROUTING
30  * iptables -t mangle -N idletimer_POSTROUTING
31  *
32  * iptables -t raw -D PREROUTING -j idletimer_PREROUTING
33  * iptables -t mangle -D POSTROUTING -j idletimer_POSTROUTING
34  *
35  *
36  * iptables -t raw -I PREROUTING -j idletimer_PREROUTING
37  * iptables -t mangle -I POSTROUTING -j idletimer_POSTROUTING
38  *
39  * # For notifications to work the lable name must match the name of a valid interface.
40  * # If the label name does match an interface, the rules will be a no-op.
41  *
42  * iptables -t raw -A idletimer_PREROUTING -i rmnet0 -j IDLETIMER  --timeout 5 --label test-chain --send_nl_msg 1
43  * iptables -t mangle -A idletimer_POSTROUTING -o rmnet0 -j IDLETIMER  --timeout 5 --label test-chain --send_nl_msg 1
44  *
45  * iptables -nxvL -t raw
46  * iptables -nxvL -t mangle
47  *
48  * =================
49  *
50  * ndc command sequence
51  * ------------------
52  * ndc idletimer enable
53  * ndc idletimer add <iface> <timeout> <class label>
54  * ndc idletimer remove <iface> <timeout> <class label>
55  *
56  * Monitor effect on the iptables chains after each step using:
57  *     iptables -nxvL -t raw
58  *     iptables -nxvL -t mangle
59  *
60  * Remember that the timeout value has to be same at the time of the
61  * removal.
62  *
63  * =================
64  *
65  * Verifying the iptables rule
66  * ---------------------------
67  * We want to make sure the iptable rules capture every packet. It can be
68  * verified with tcpdump. First take a note of the pkts count for the two rules:
69  *
70  * adb shell iptables -t mangle -L idletimer_mangle_POSTROUTING -v && adb shell iptables -t raw -L idletimer_raw_PREROUTING -v
71  *
72  * And then, before any network traffics happen on the device, run tcpdump:
73  *
74  * adb shell tcpdump | tee tcpdump.log
75  *
76  * After a while run iptables commands again, you could then count the number
77  * of incoming and outgoing packets captured by tcpdump, and compare that with
78  * the numbers reported by iptables command. There shouldn't be too much
79  * difference on these numbers, i.e., with 2000 packets captured it should
80  * differ by less than 5.
81  *
82  * =================
83  *
84  * Note that currently if the name of the iface is incorrect, iptables
85  * will setup rules without checking if it is the name of a valid
86  * interface (although no notifications will ever be received).  It is
87  * the responsibility of code in Java land to ensure that the interface name
88  * is correct. The benefit of this, is that idletimers can be setup on
89  * interfaces than come and go.
90  *
91  * A remove should be called for each add command issued during cleanup, as duplicate
92  * entries of the rule may exist and will all have to removed.
93  *
94  */
95 
96 #define LOG_NDEBUG 0
97 
98 #include <stdlib.h>
99 #include <errno.h>
100 #include <sys/socket.h>
101 #include <sys/stat.h>
102 #include <sys/wait.h>
103 #include <fcntl.h>
104 #include <netinet/in.h>
105 #include <arpa/inet.h>
106 #include <string.h>
107 #include <cutils/properties.h>
108 
109 #define LOG_TAG "IdletimerController"
110 #include <cutils/log.h>
111 #include <logwrap/logwrap.h>
112 
113 #include "IdletimerController.h"
114 #include "NetdConstants.h"
115 
116 const char* IdletimerController::LOCAL_RAW_PREROUTING = "idletimer_raw_PREROUTING";
117 const char* IdletimerController::LOCAL_MANGLE_POSTROUTING = "idletimer_mangle_POSTROUTING";
118 
IdletimerController()119 IdletimerController::IdletimerController() {
120 }
121 
~IdletimerController()122 IdletimerController::~IdletimerController() {
123 }
124 /* return 0 or non-zero */
runIpxtablesCmd(int argc,const char ** argv)125 int IdletimerController::runIpxtablesCmd(int argc, const char **argv) {
126     int resIpv4, resIpv6;
127 
128     // Running for IPv4
129     argv[0] = IPTABLES_PATH;
130     resIpv4 = android_fork_execvp(argc, (char **)argv, NULL, false, false);
131 
132     // Running for IPv6
133     argv[0] = IP6TABLES_PATH;
134     resIpv6 = android_fork_execvp(argc, (char **)argv, NULL, false, false);
135 
136 #if !LOG_NDEBUG
137     std::string full_cmd = argv[0];
138     argc--; argv++;
139     for (; argc; argc--, argv++) {
140         full_cmd += " ";
141         full_cmd += argv[0];
142     }
143     ALOGV("runCmd(%s) res_ipv4=%d, res_ipv6=%d", full_cmd.c_str(), resIpv4, resIpv6);
144 #endif
145 
146     return (resIpv4 == 0 && resIpv6 == 0) ? 0 : -1;
147 }
148 
setupIptablesHooks()149 bool IdletimerController::setupIptablesHooks() {
150     return true;
151 }
152 
setDefaults()153 int IdletimerController::setDefaults() {
154   int res;
155   const char *cmd1[] = {
156       NULL, // To be filled inside runIpxtablesCmd
157       "-w",
158       "-t",
159       "raw",
160       "-F",
161       LOCAL_RAW_PREROUTING
162   };
163   res = runIpxtablesCmd(ARRAY_SIZE(cmd1), cmd1);
164 
165   if (res)
166     return res;
167 
168   const char *cmd2[] = {
169       NULL, // To be filled inside runIpxtablesCmd
170       "-w",
171       "-t",
172       "mangle",
173       "-F",
174       LOCAL_MANGLE_POSTROUTING
175   };
176   res = runIpxtablesCmd(ARRAY_SIZE(cmd2), cmd2);
177 
178   return res;
179 }
180 
enableIdletimerControl()181 int IdletimerController::enableIdletimerControl() {
182     int res = setDefaults();
183     return res;
184 }
185 
disableIdletimerControl()186 int IdletimerController::disableIdletimerControl() {
187     int res = setDefaults();
188     return res;
189 }
190 
modifyInterfaceIdletimer(IptOp op,const char * iface,uint32_t timeout,const char * classLabel)191 int IdletimerController::modifyInterfaceIdletimer(IptOp op, const char *iface,
192                                                   uint32_t timeout,
193                                                   const char *classLabel) {
194   int res;
195   char timeout_str[11]; //enough to store any 32-bit unsigned decimal
196 
197   if (!isIfaceName(iface)) {
198     errno = ENOENT;
199     return -1;
200   }
201 
202   snprintf(timeout_str, sizeof(timeout_str), "%u", timeout);
203 
204   const char *cmd1[] = {
205       NULL, // To be filled inside runIpxtablesCmd
206       "-w",
207       "-t",
208       "raw",
209       (op == IptOpAdd) ? "-A" : "-D",
210       LOCAL_RAW_PREROUTING,
211       "-i",
212       iface,
213       "-j",
214       "IDLETIMER",
215       "--timeout",
216       timeout_str,
217       "--label",
218       classLabel,
219       "--send_nl_msg",
220       "1"
221   };
222   res = runIpxtablesCmd(ARRAY_SIZE(cmd1), cmd1);
223 
224   if (res)
225     return res;
226 
227   const char *cmd2[] = {
228       NULL, // To be filled inside runIpxtablesCmd
229       "-w",
230       "-t",
231       "mangle",
232       (op == IptOpAdd) ? "-A" : "-D",
233       LOCAL_MANGLE_POSTROUTING,
234       "-o",
235       iface,
236       "-j",
237       "IDLETIMER",
238       "--timeout",
239       timeout_str,
240       "--label",
241       classLabel,
242       "--send_nl_msg",
243       "1"
244   };
245   res = runIpxtablesCmd(ARRAY_SIZE(cmd2), cmd2);
246 
247   return res;
248 }
249 
addInterfaceIdletimer(const char * iface,uint32_t timeout,const char * classLabel)250 int IdletimerController::addInterfaceIdletimer(const char *iface,
251                                                uint32_t timeout,
252                                                const char *classLabel) {
253   return modifyInterfaceIdletimer(IptOpAdd, iface, timeout, classLabel);
254 }
255 
removeInterfaceIdletimer(const char * iface,uint32_t timeout,const char * classLabel)256 int IdletimerController::removeInterfaceIdletimer(const char *iface,
257                                                   uint32_t timeout,
258                                                   const char *classLabel) {
259   return modifyInterfaceIdletimer(IptOpDelete, iface, timeout, classLabel);
260 }
261