Home | History | Annotate | Download | only in netd
      1 /*
      2  * Copyright (C) 2008 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 #include <stdlib.h>
     18 #include <errno.h>
     19 #include <fcntl.h>
     20 #include <string.h>
     21 
     22 #include <sys/socket.h>
     23 #include <sys/stat.h>
     24 #include <sys/types.h>
     25 #include <sys/wait.h>
     26 
     27 #include <netinet/in.h>
     28 #include <arpa/inet.h>
     29 
     30 #define LOG_TAG "SecondaryTablController"
     31 #include <cutils/log.h>
     32 #include <cutils/properties.h>
     33 #include <logwrap/logwrap.h>
     34 
     35 #include "ResponseCode.h"
     36 #include "NetdConstants.h"
     37 #include "SecondaryTableController.h"
     38 
     39 SecondaryTableController::SecondaryTableController() {
     40     int i;
     41     for (i=0; i < INTERFACES_TRACKED; i++) {
     42         mInterfaceTable[i][0] = 0;
     43         // TODO - use a hashtable or other prebuilt container class
     44         mInterfaceRuleCount[i] = 0;
     45     }
     46 }
     47 
     48 SecondaryTableController::~SecondaryTableController() {
     49 }
     50 
     51 int SecondaryTableController::findTableNumber(const char *iface) {
     52     int i;
     53     for (i = 0; i < INTERFACES_TRACKED; i++) {
     54         // compare through the final null, hence +1
     55         if (strncmp(iface, mInterfaceTable[i], IFNAMSIZ + 1) == 0) {
     56             return i;
     57         }
     58     }
     59     return -1;
     60 }
     61 
     62 int SecondaryTableController::addRoute(SocketClient *cli, char *iface, char *dest, int prefix,
     63         char *gateway) {
     64     int tableIndex = findTableNumber(iface);
     65     if (tableIndex == -1) {
     66         tableIndex = findTableNumber(""); // look for an empty slot
     67         if (tableIndex == -1) {
     68             ALOGE("Max number of NATed interfaces reached");
     69             errno = ENODEV;
     70             cli->sendMsg(ResponseCode::OperationFailed, "Max number NATed", true);
     71             return -1;
     72         }
     73         strncpy(mInterfaceTable[tableIndex], iface, IFNAMSIZ);
     74         // Ensure null termination even if truncation happened
     75         mInterfaceTable[tableIndex][IFNAMSIZ] = 0;
     76     }
     77 
     78     return modifyRoute(cli, ADD, iface, dest, prefix, gateway, tableIndex);
     79 }
     80 
     81 int SecondaryTableController::modifyRoute(SocketClient *cli, const char *action, char *iface,
     82         char *dest, int prefix, char *gateway, int tableIndex) {
     83     char dest_str[44]; // enough to store an IPv6 address + 3 character bitmask
     84     char tableIndex_str[11];
     85     int ret;
     86 
     87     //  IP tool doesn't like "::" - the equiv of 0.0.0.0 that it accepts for ipv4
     88     snprintf(dest_str, sizeof(dest_str), "%s/%d", dest, prefix);
     89     snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex + BASE_TABLE_NUMBER);
     90 
     91     if (strcmp("::", gateway) == 0) {
     92         const char *cmd[] = {
     93                 IP_PATH,
     94                 "route",
     95                 action,
     96                 dest_str,
     97                 "dev",
     98                 iface,
     99                 "table",
    100                 tableIndex_str
    101         };
    102         ret = runCmd(ARRAY_SIZE(cmd), cmd);
    103     } else {
    104         const char *cmd[] = {
    105                 IP_PATH,
    106                 "route",
    107                 action,
    108                 dest_str,
    109                 "via",
    110                 gateway,
    111                 "dev",
    112                 iface,
    113                 "table",
    114                 tableIndex_str
    115         };
    116         ret = runCmd(ARRAY_SIZE(cmd), cmd);
    117     }
    118 
    119     if (ret) {
    120         ALOGE("ip route %s failed: %s route %s %s/%d via %s dev %s table %d", action,
    121                 IP_PATH, action, dest, prefix, gateway, iface, tableIndex+BASE_TABLE_NUMBER);
    122         errno = ENODEV;
    123         cli->sendMsg(ResponseCode::OperationFailed, "ip route modification failed", true);
    124         return -1;
    125     }
    126 
    127     if (strcmp(action, ADD) == 0) {
    128         mInterfaceRuleCount[tableIndex]++;
    129     } else {
    130         if (--mInterfaceRuleCount[tableIndex] < 1) {
    131             mInterfaceRuleCount[tableIndex] = 0;
    132             mInterfaceTable[tableIndex][0] = 0;
    133         }
    134     }
    135     modifyRuleCount(tableIndex, action);
    136     cli->sendMsg(ResponseCode::CommandOkay, "Route modified", false);
    137     return 0;
    138 }
    139 
    140 void SecondaryTableController::modifyRuleCount(int tableIndex, const char *action) {
    141     if (strcmp(action, ADD) == 0) {
    142         mInterfaceRuleCount[tableIndex]++;
    143     } else {
    144         if (--mInterfaceRuleCount[tableIndex] < 1) {
    145             mInterfaceRuleCount[tableIndex] = 0;
    146             mInterfaceTable[tableIndex][0] = 0;
    147         }
    148     }
    149 }
    150 
    151 int SecondaryTableController::verifyTableIndex(int tableIndex) {
    152     if ((tableIndex < 0) ||
    153             (tableIndex >= INTERFACES_TRACKED) ||
    154             (mInterfaceTable[tableIndex][0] == 0)) {
    155         return -1;
    156     } else {
    157         return 0;
    158     }
    159 }
    160 
    161 const char *SecondaryTableController::getVersion(const char *addr) {
    162     if (strchr(addr, ':') != NULL) {
    163         return "-6";
    164     } else {
    165         return "-4";
    166     }
    167 }
    168 
    169 int SecondaryTableController::removeRoute(SocketClient *cli, char *iface, char *dest, int prefix,
    170         char *gateway) {
    171     int tableIndex = findTableNumber(iface);
    172     if (tableIndex == -1) {
    173         ALOGE("Interface not found");
    174         errno = ENODEV;
    175         cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
    176         return -1;
    177     }
    178 
    179     return modifyRoute(cli, DEL, iface, dest, prefix, gateway, tableIndex);
    180 }
    181 
    182 int SecondaryTableController::modifyFromRule(int tableIndex, const char *action,
    183         const char *addr) {
    184     char tableIndex_str[11];
    185 
    186     if (verifyTableIndex(tableIndex)) {
    187         return -1;
    188     }
    189 
    190     snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex +
    191             BASE_TABLE_NUMBER);
    192     const char *cmd[] = {
    193             IP_PATH,
    194             getVersion(addr),
    195             "rule",
    196             action,
    197             "from",
    198             addr,
    199             "table",
    200             tableIndex_str
    201     };
    202     if (runCmd(ARRAY_SIZE(cmd), cmd)) {
    203         return -1;
    204     }
    205 
    206     modifyRuleCount(tableIndex, action);
    207     return 0;
    208 }
    209 
    210 int SecondaryTableController::modifyLocalRoute(int tableIndex, const char *action,
    211         const char *iface, const char *addr) {
    212     char tableIndex_str[11];
    213 
    214     if (verifyTableIndex(tableIndex)) {
    215         return -1;
    216     }
    217 
    218     modifyRuleCount(tableIndex, action); // some del's will fail as the iface is already gone.
    219 
    220     snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex +
    221             BASE_TABLE_NUMBER);
    222     const char *cmd[] = {
    223             IP_PATH,
    224             "route",
    225             action,
    226             addr,
    227             "dev",
    228             iface,
    229             "table",
    230             tableIndex_str
    231     };
    232 
    233     return runCmd(ARRAY_SIZE(cmd), cmd);
    234 }
    235 
    236 int SecondaryTableController::runCmd(int argc, const char **argv) {
    237     int ret = 0;
    238 
    239     ret = android_fork_execvp(argc, (char **)argv, NULL, false, false);
    240     return ret;
    241 }
    242