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