SecondaryTableController.cpp revision 3c20787d7935c2016e8e3cc49d8f15647c12c41c
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 34extern "C" int system_nosh(const char *command); 35 36#include "ResponseCode.h" 37#include "SecondaryTableController.h" 38 39static char IP_PATH[] = "/system/bin/ip"; 40static char ADD[] = "add"; 41static char DEL[] = "del"; 42 43SecondaryTableController::SecondaryTableController() { 44 int i; 45 for (i=0; i < INTERFACES_TRACKED; i++) { 46 mInterfaceTable[i][0] = 0; 47 // TODO - use a hashtable or other prebuilt container class 48 mInterfaceRuleCount[i] = 0; 49 } 50} 51 52SecondaryTableController::~SecondaryTableController() { 53} 54 55int SecondaryTableController::findTableNumber(const char *iface) { 56 int i; 57 for (i = 0; i < INTERFACES_TRACKED; i++) { 58 // compare through the final null, hence +1 59 if (strncmp(iface, mInterfaceTable[i], IFNAMSIZ + 1) == 0) { 60 return i; 61 } 62 } 63 return -1; 64} 65 66int SecondaryTableController::addRoute(SocketClient *cli, char *iface, char *dest, int prefix, 67 char *gateway) { 68 int tableIndex = findTableNumber(iface); 69 if (tableIndex == -1) { 70 tableIndex = findTableNumber(""); // look for an empty slot 71 if (tableIndex == -1) { 72 LOGE("Max number of NATed interfaces reached"); 73 errno = ENODEV; 74 cli->sendMsg(ResponseCode::OperationFailed, "Max number NATed", true); 75 return -1; 76 } 77 strncpy(mInterfaceTable[tableIndex], iface, IFNAMSIZ); 78 // Ensure null termination even if truncation happened 79 mInterfaceTable[tableIndex][IFNAMSIZ] = 0; 80 } 81 82 return modifyRoute(cli, ADD, iface, dest, prefix, gateway, tableIndex); 83} 84 85int SecondaryTableController::modifyRoute(SocketClient *cli, char *action, char *iface, char *dest, 86 int prefix, char *gateway, int tableIndex) { 87 char *cmd; 88 89 if (strcmp("::", gateway) == 0) { 90 // IP tool doesn't like "::" - the equiv of 0.0.0.0 that it accepts for ipv4 91 asprintf(&cmd, "%s route %s %s/%d dev %s table %d", 92 IP_PATH, action, dest, prefix, iface, tableIndex+BASE_TABLE_NUMBER); 93 } else { 94 asprintf(&cmd, "%s route %s %s/%d via %s dev %s table %d", 95 IP_PATH, action, dest, prefix, gateway, iface, tableIndex+BASE_TABLE_NUMBER); 96 } 97 98 if (runAndFree(cli, cmd)) { 99 LOGE("ip route %s failed: %s route %s %s/%d via %s dev %s table %d", action, 100 IP_PATH, action, dest, prefix, gateway, iface, tableIndex+BASE_TABLE_NUMBER); 101 errno = ENODEV; 102 cli->sendMsg(ResponseCode::OperationFailed, "ip route modification failed", true); 103 return -1; 104 } 105 106 if (strcmp(action, ADD) == 0) { 107 mInterfaceRuleCount[tableIndex]++; 108 } else { 109 if (--mInterfaceRuleCount[tableIndex] < 1) { 110 mInterfaceRuleCount[tableIndex] = 0; 111 mInterfaceTable[tableIndex][0] = 0; 112 } 113 } 114 cli->sendMsg(ResponseCode::CommandOkay, "Route modified", false); 115 return 0; 116} 117 118int SecondaryTableController::removeRoute(SocketClient *cli, char *iface, char *dest, int prefix, 119 char *gateway) { 120 int tableIndex = findTableNumber(iface); 121 if (tableIndex == -1) { 122 LOGE("Interface not found"); 123 errno = ENODEV; 124 cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true); 125 return -1; 126 } 127 128 return modifyRoute(cli, DEL, iface, dest, prefix, gateway, tableIndex); 129} 130 131int SecondaryTableController::runAndFree(SocketClient *cli, char *cmd) { 132 int ret = 0; 133 if (strlen(cmd) >= 255) { 134 LOGE("ip command (%s) too long", cmd); 135 errno = E2BIG; 136 cli->sendMsg(ResponseCode::CommandSyntaxError, "Too long", true); 137 free(cmd); 138 return -1; 139 } 140 ret = system_nosh(cmd); 141 free(cmd); 142 return ret; 143} 144