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