Home | History | Annotate | Download | only in server
      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 
    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 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 
    149 bool IdletimerController::setupIptablesHooks() {
    150     return true;
    151 }
    152 
    153 int IdletimerController::setDefaults() {
    154   int res;
    155   const char *cmd1[] = {
    156       NULL, // To be filled inside runIpxtablesCmd
    157       "-t",
    158       "raw",
    159       "-F",
    160       LOCAL_RAW_PREROUTING
    161   };
    162   res = runIpxtablesCmd(ARRAY_SIZE(cmd1), cmd1);
    163 
    164   if (res)
    165     return res;
    166 
    167   const char *cmd2[] = {
    168       NULL, // To be filled inside runIpxtablesCmd
    169       "-t",
    170       "mangle",
    171       "-F",
    172       LOCAL_MANGLE_POSTROUTING
    173   };
    174   res = runIpxtablesCmd(ARRAY_SIZE(cmd2), cmd2);
    175 
    176   return res;
    177 }
    178 
    179 int IdletimerController::enableIdletimerControl() {
    180     int res = setDefaults();
    181     return res;
    182 }
    183 
    184 int IdletimerController::disableIdletimerControl() {
    185     int res = setDefaults();
    186     return res;
    187 }
    188 
    189 int IdletimerController::modifyInterfaceIdletimer(IptOp op, const char *iface,
    190                                                   uint32_t timeout,
    191                                                   const char *classLabel) {
    192   int res;
    193   char timeout_str[11]; //enough to store any 32-bit unsigned decimal
    194 
    195   if (!isIfaceName(iface)) {
    196     errno = ENOENT;
    197     return -1;
    198   }
    199 
    200   snprintf(timeout_str, sizeof(timeout_str), "%u", timeout);
    201 
    202   const char *cmd1[] = {
    203       NULL, // To be filled inside runIpxtablesCmd
    204       "-t",
    205       "raw",
    206       (op == IptOpAdd) ? "-A" : "-D",
    207       LOCAL_RAW_PREROUTING,
    208       "-i",
    209       iface,
    210       "-j",
    211       "IDLETIMER",
    212       "--timeout",
    213       timeout_str,
    214       "--label",
    215       classLabel,
    216       "--send_nl_msg",
    217       "1"
    218   };
    219   res = runIpxtablesCmd(ARRAY_SIZE(cmd1), cmd1);
    220 
    221   if (res)
    222     return res;
    223 
    224   const char *cmd2[] = {
    225       NULL, // To be filled inside runIpxtablesCmd
    226       "-t",
    227       "mangle",
    228       (op == IptOpAdd) ? "-A" : "-D",
    229       LOCAL_MANGLE_POSTROUTING,
    230       "-o",
    231       iface,
    232       "-j",
    233       "IDLETIMER",
    234       "--timeout",
    235       timeout_str,
    236       "--label",
    237       classLabel,
    238       "--send_nl_msg",
    239       "1"
    240   };
    241   res = runIpxtablesCmd(ARRAY_SIZE(cmd2), cmd2);
    242 
    243   return res;
    244 }
    245 
    246 int IdletimerController::addInterfaceIdletimer(const char *iface,
    247                                                uint32_t timeout,
    248                                                const char *classLabel) {
    249   return modifyInterfaceIdletimer(IptOpAdd, iface, timeout, classLabel);
    250 }
    251 
    252 int IdletimerController::removeInterfaceIdletimer(const char *iface,
    253                                                   uint32_t timeout,
    254                                                   const char *classLabel) {
    255   return modifyInterfaceIdletimer(IptOpDelete, iface, timeout, classLabel);
    256 }
    257