SecondaryTableController.cpp revision 063af322b48ab1bb0c3e09eb0b64915ba568275b
1a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner/* 2a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner * Copyright (C) 2008 The Android Open Source Project 3a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner * 4a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner * Licensed under the Apache License, Version 2.0 (the "License"); 5a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner * you may not use this file except in compliance with the License. 6a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner * You may obtain a copy of the License at 7a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner * 8a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner * http://www.apache.org/licenses/LICENSE-2.0 9a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner * 10a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner * Unless required by applicable law or agreed to in writing, software 11a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner * distributed under the License is distributed on an "AS IS" BASIS, 12a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner * See the License for the specific language governing permissions and 14a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner * limitations under the License. 15a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner */ 16a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 17a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner#include <stdlib.h> 18a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner#include <errno.h> 19a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner#include <fcntl.h> 20a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner#include <string.h> 21a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 22a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner#include <sys/socket.h> 23a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner#include <sys/stat.h> 24a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner#include <sys/types.h> 25a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner#include <sys/wait.h> 26a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 27a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner#include <netinet/in.h> 28a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner#include <arpa/inet.h> 29a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 30a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner#define LOG_TAG "SecondaryTablController" 31a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner#include <cutils/log.h> 32a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner#include <cutils/properties.h> 33a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 34a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner#include "ResponseCode.h" 35a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner#include "SecondaryTableController.h" 36a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 37a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turnerstatic char IP_PATH[] = "/system/bin/ip"; 38a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turnerstatic char ADD[] = "add"; 39a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turnerstatic char DEL[] = "del"; 40a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 41a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' TurnerSecondaryTableController::SecondaryTableController() { 42a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner int i; 43a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner for (i=0; i < INTERFACES_TRACKED; i++) { 44a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner mInterfaceTable[i][0] = 0; 45a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner // TODO - use a hashtable or other prebuilt container class 46a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner mInterfaceRuleCount[i] = 0; 47a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner } 48a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner} 49a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 50a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' TurnerSecondaryTableController::~SecondaryTableController() { 51a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner} 52a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 53a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turnerint SecondaryTableController::findTableNumber(const char *iface) { 54a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner int i; 55a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner for (i = 0; i < INTERFACES_TRACKED; i++) { 56a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner if (strncmp(iface, mInterfaceTable[i], MAX_IFACE_LENGTH) == 0) { 57a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner return i; 58a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner } 59a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner } 60a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner return -1; 61a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner} 62a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 63a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turnerint SecondaryTableController::addRoute(SocketClient *cli, char *iface, char *dest, int prefix, 64a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner char *gateway) { 65a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner int tableIndex = findTableNumber(iface); 66a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner if (tableIndex == -1) { 67a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner tableIndex = findTableNumber(""); // look for an empty slot 68a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner if (tableIndex == -1) { 69a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner LOGE("Max number of NATed interfaces reached"); 70a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner errno = ENODEV; 71a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner cli->sendMsg(ResponseCode::OperationFailed, "Max number NATed", true); 72a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner return -1; 73a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner } 74a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner strncpy(mInterfaceTable[tableIndex], iface, MAX_IFACE_LENGTH); 75a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner } 76a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 77a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner return modifyRoute(cli, ADD, iface, dest, prefix, gateway, tableIndex); 78a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner} 79a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 80a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turnerint SecondaryTableController::modifyRoute(SocketClient *cli, char *action, char *iface, char *dest, 81a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner int prefix, char *gateway, int tableIndex) { 82a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner char *cmd; 83a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 84a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner if (strcmp("::", gateway) == 0) { 85a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner // IP tool doesn't like "::" - the equiv of 0.0.0.0 that it accepts for ipv4 86a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner asprintf(&cmd, "%s route %s %s/%d dev %s table %d", 87a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner IP_PATH, action, dest, prefix, iface, tableIndex+BASE_TABLE_NUMBER); 88a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner } else { 89a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner asprintf(&cmd, "%s route %s %s/%d via %s dev %s table %d", 90a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner IP_PATH, action, dest, prefix, gateway, iface, tableIndex+BASE_TABLE_NUMBER); 91a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner } 92a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 93a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner if (runAndFree(cli, cmd)) { 94a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner LOGE("ip route %s failed: %s route %s %s/%d via %s dev %s table %d", action, 95a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner IP_PATH, action, dest, prefix, gateway, iface, tableIndex+BASE_TABLE_NUMBER); 96a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner errno = ENODEV; 97a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner cli->sendMsg(ResponseCode::OperationFailed, "ip route modification failed", true); 98a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner return -1; 99a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner } 100a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 101a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner if (strcmp(action, ADD) == 0) { 102a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner mInterfaceRuleCount[tableIndex]++; 103a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner } else { 104a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner if (--mInterfaceRuleCount[tableIndex] < 1) { 105a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner mInterfaceRuleCount[tableIndex] = 0; 106a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner mInterfaceTable[tableIndex][0] = 0; 107a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner } 108a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner } 109a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner cli->sendMsg(ResponseCode::CommandOkay, "Route modified", false); 110a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner return 0; 111a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner} 112a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 113a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turnerint SecondaryTableController::removeRoute(SocketClient *cli, char *iface, char *dest, int prefix, 114a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner char *gateway) { 115a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner int tableIndex = findTableNumber(iface); 116a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner if (tableIndex == -1) { 117a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner LOGE("Interface not found"); 118a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner errno = ENODEV; 119a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true); 120a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner return -1; 121a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner } 122a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 123a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner return modifyRoute(cli, DEL, iface, dest, prefix, gateway, tableIndex); 124a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner} 125a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner 126a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turnerint SecondaryTableController::runAndFree(SocketClient *cli, char *cmd) { 127a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner int ret = 0; 128a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner if (strlen(cmd) >= 255) { 129a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner LOGE("ip command (%s) too long", cmd); 130a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner errno = E2BIG; 131a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner cli->sendMsg(ResponseCode::CommandSyntaxError, "Too long", true); 132a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner free(cmd); 133a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner return -1; 134a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner } 135a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner ret = system(cmd); 136a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner free(cmd); 137a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner return ret; 138a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner} 139a4502d4e775e9038621cf32dd311ee6afa788dd0David 'Digit' Turner