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