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       "-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 
    181 int IdletimerController::enableIdletimerControl() {
    182     int res = setDefaults();
    183     return res;
    184 }
    185 
    186 int IdletimerController::disableIdletimerControl() {
    187     int res = setDefaults();
    188     return res;
    189 }
    190 
    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 
    250 int IdletimerController::addInterfaceIdletimer(const char *iface,
    251                                                uint32_t timeout,
    252                                                const char *classLabel) {
    253   return modifyInterfaceIdletimer(IptOpAdd, iface, timeout, classLabel);
    254 }
    255 
    256 int IdletimerController::removeInterfaceIdletimer(const char *iface,
    257                                                   uint32_t timeout,
    258                                                   const char *classLabel) {
    259   return modifyInterfaceIdletimer(IptOpDelete, iface, timeout, classLabel);
    260 }
    261