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 "TetherController"
31#include <cutils/log.h>
32#include <cutils/properties.h>
33
34#include "Fwmark.h"
35#include "NetdConstants.h"
36#include "Permission.h"
37#include "TetherController.h"
38
39namespace {
40
41static const char BP_TOOLS_MODE[] = "bp-tools";
42static const char IPV4_FORWARDING_PROC_FILE[] = "/proc/sys/net/ipv4/ip_forward";
43static const char IPV6_FORWARDING_PROC_FILE[] = "/proc/sys/net/ipv6/conf/all/forwarding";
44
45bool writeToFile(const char* filename, const char* value) {
46    int fd = open(filename, O_WRONLY);
47    if (fd < 0) {
48        ALOGE("Failed to open %s: %s", filename, strerror(errno));
49        return false;
50    }
51
52    const ssize_t len = strlen(value);
53    if (write(fd, value, len) != len) {
54        ALOGE("Failed to write %s to %s: %s", value, filename, strerror(errno));
55        close(fd);
56        return false;
57    }
58    close(fd);
59    return true;
60}
61
62bool inBpToolsMode() {
63    // In BP tools mode, do not disable IP forwarding
64    char bootmode[PROPERTY_VALUE_MAX] = {0};
65    property_get("ro.bootmode", bootmode, "unknown");
66    return !strcmp(BP_TOOLS_MODE, bootmode);
67}
68
69}  // namespace
70
71TetherController::TetherController() {
72    mInterfaces = new InterfaceCollection();
73    mDnsNetId = 0;
74    mDnsForwarders = new NetAddressCollection();
75    mDaemonFd = -1;
76    mDaemonPid = 0;
77    if (inBpToolsMode()) {
78        enableForwarding(BP_TOOLS_MODE);
79    } else {
80        setIpFwdEnabled();
81    }
82}
83
84TetherController::~TetherController() {
85    InterfaceCollection::iterator it;
86
87    for (it = mInterfaces->begin(); it != mInterfaces->end(); ++it) {
88        free(*it);
89    }
90    mInterfaces->clear();
91
92    mDnsForwarders->clear();
93    mForwardingRequests.clear();
94}
95
96bool TetherController::setIpFwdEnabled() {
97    bool success = true;
98    const char* value = mForwardingRequests.empty() ? "0" : "1";
99    ALOGD("Setting IP forward enable = %s", value);
100    success &= writeToFile(IPV4_FORWARDING_PROC_FILE, value);
101    success &= writeToFile(IPV6_FORWARDING_PROC_FILE, value);
102    return success;
103}
104
105bool TetherController::enableForwarding(const char* requester) {
106    // Don't return an error if this requester already requested forwarding. Only return errors for
107    // things that the caller caller needs to care about, such as "couldn't write to the file to
108    // enable forwarding".
109    mForwardingRequests.insert(requester);
110    return setIpFwdEnabled();
111}
112
113bool TetherController::disableForwarding(const char* requester) {
114    mForwardingRequests.erase(requester);
115    return setIpFwdEnabled();
116}
117
118size_t TetherController::forwardingRequestCount() {
119    return mForwardingRequests.size();
120}
121
122#define TETHER_START_CONST_ARG        8
123
124int TetherController::startTethering(int num_addrs, struct in_addr* addrs) {
125    if (mDaemonPid != 0) {
126        ALOGE("Tethering already started");
127        errno = EBUSY;
128        return -1;
129    }
130
131    ALOGD("Starting tethering services");
132
133    pid_t pid;
134    int pipefd[2];
135
136    if (pipe(pipefd) < 0) {
137        ALOGE("pipe failed (%s)", strerror(errno));
138        return -1;
139    }
140
141    /*
142     * TODO: Create a monitoring thread to handle and restart
143     * the daemon if it exits prematurely
144     */
145    if ((pid = fork()) < 0) {
146        ALOGE("fork failed (%s)", strerror(errno));
147        close(pipefd[0]);
148        close(pipefd[1]);
149        return -1;
150    }
151
152    if (!pid) {
153        close(pipefd[1]);
154        if (pipefd[0] != STDIN_FILENO) {
155            if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
156                ALOGE("dup2 failed (%s)", strerror(errno));
157                return -1;
158            }
159            close(pipefd[0]);
160        }
161
162        int num_processed_args = TETHER_START_CONST_ARG + (num_addrs/2) + 1;
163        char **args = (char **)malloc(sizeof(char *) * num_processed_args);
164        args[num_processed_args - 1] = NULL;
165        args[0] = (char *)"/system/bin/dnsmasq";
166        args[1] = (char *)"--keep-in-foreground";
167        args[2] = (char *)"--no-resolv";
168        args[3] = (char *)"--no-poll";
169        args[4] = (char *)"--dhcp-authoritative";
170        // TODO: pipe through metered status from ConnService
171        args[5] = (char *)"--dhcp-option-force=43,ANDROID_METERED";
172        args[6] = (char *)"--pid-file";
173        args[7] = (char *)"";
174
175        int nextArg = TETHER_START_CONST_ARG;
176        for (int addrIndex=0; addrIndex < num_addrs;) {
177            char *start = strdup(inet_ntoa(addrs[addrIndex++]));
178            char *end = strdup(inet_ntoa(addrs[addrIndex++]));
179            asprintf(&(args[nextArg++]),"--dhcp-range=%s,%s,1h", start, end);
180            free(start);
181            free(end);
182        }
183
184        if (execv(args[0], args)) {
185            ALOGE("execl failed (%s)", strerror(errno));
186        }
187        ALOGE("Should never get here!");
188        _exit(-1);
189    } else {
190        close(pipefd[0]);
191        mDaemonPid = pid;
192        mDaemonFd = pipefd[1];
193        applyDnsInterfaces();
194        ALOGD("Tethering services running");
195    }
196
197    return 0;
198}
199
200int TetherController::stopTethering() {
201
202    if (mDaemonPid == 0) {
203        ALOGE("Tethering already stopped");
204        return 0;
205    }
206
207    ALOGD("Stopping tethering services");
208
209    kill(mDaemonPid, SIGTERM);
210    waitpid(mDaemonPid, NULL, 0);
211    mDaemonPid = 0;
212    close(mDaemonFd);
213    mDaemonFd = -1;
214    ALOGD("Tethering services stopped");
215    return 0;
216}
217
218bool TetherController::isTetheringStarted() {
219    return (mDaemonPid == 0 ? false : true);
220}
221
222#define MAX_CMD_SIZE 1024
223
224int TetherController::setDnsForwarders(unsigned netId, char **servers, int numServers) {
225    int i;
226    char daemonCmd[MAX_CMD_SIZE];
227
228    Fwmark fwmark;
229    fwmark.netId = netId;
230    fwmark.explicitlySelected = true;
231    fwmark.protectedFromVpn = true;
232    fwmark.permission = PERMISSION_SYSTEM;
233
234    snprintf(daemonCmd, sizeof(daemonCmd), "update_dns:0x%x", fwmark.intValue);
235    int cmdLen = strlen(daemonCmd);
236
237    mDnsForwarders->clear();
238    for (i = 0; i < numServers; i++) {
239        ALOGD("setDnsForwarders(0x%x %d = '%s')", fwmark.intValue, i, servers[i]);
240
241        struct in_addr a;
242
243        if (!inet_aton(servers[i], &a)) {
244            ALOGE("Failed to parse DNS server '%s'", servers[i]);
245            mDnsForwarders->clear();
246            return -1;
247        }
248
249        cmdLen += (strlen(servers[i]) + 1);
250        if (cmdLen + 1 >= MAX_CMD_SIZE) {
251            ALOGD("Too many DNS servers listed");
252            break;
253        }
254
255        strcat(daemonCmd, ":");
256        strcat(daemonCmd, servers[i]);
257        mDnsForwarders->push_back(a);
258    }
259
260    mDnsNetId = netId;
261    if (mDaemonFd != -1) {
262        ALOGD("Sending update msg to dnsmasq [%s]", daemonCmd);
263        if (write(mDaemonFd, daemonCmd, strlen(daemonCmd) +1) < 0) {
264            ALOGE("Failed to send update command to dnsmasq (%s)", strerror(errno));
265            mDnsForwarders->clear();
266            return -1;
267        }
268    }
269    return 0;
270}
271
272unsigned TetherController::getDnsNetId() {
273    return mDnsNetId;
274}
275
276NetAddressCollection *TetherController::getDnsForwarders() {
277    return mDnsForwarders;
278}
279
280int TetherController::applyDnsInterfaces() {
281    char daemonCmd[MAX_CMD_SIZE];
282
283    strcpy(daemonCmd, "update_ifaces");
284    int cmdLen = strlen(daemonCmd);
285    InterfaceCollection::iterator it;
286    bool haveInterfaces = false;
287
288    for (it = mInterfaces->begin(); it != mInterfaces->end(); ++it) {
289        cmdLen += (strlen(*it) + 1);
290        if (cmdLen + 1 >= MAX_CMD_SIZE) {
291            ALOGD("Too many DNS ifaces listed");
292            break;
293        }
294
295        strcat(daemonCmd, ":");
296        strcat(daemonCmd, *it);
297        haveInterfaces = true;
298    }
299
300    if ((mDaemonFd != -1) && haveInterfaces) {
301        ALOGD("Sending update msg to dnsmasq [%s]", daemonCmd);
302        if (write(mDaemonFd, daemonCmd, strlen(daemonCmd) +1) < 0) {
303            ALOGE("Failed to send update command to dnsmasq (%s)", strerror(errno));
304            return -1;
305        }
306    }
307    return 0;
308}
309
310int TetherController::tetherInterface(const char *interface) {
311    ALOGD("tetherInterface(%s)", interface);
312    if (!isIfaceName(interface)) {
313        errno = ENOENT;
314        return -1;
315    }
316    mInterfaces->push_back(strdup(interface));
317
318    if (applyDnsInterfaces()) {
319        InterfaceCollection::iterator it;
320        for (it = mInterfaces->begin(); it != mInterfaces->end(); ++it) {
321            if (!strcmp(interface, *it)) {
322                free(*it);
323                mInterfaces->erase(it);
324                break;
325            }
326        }
327        return -1;
328    } else {
329        return 0;
330    }
331}
332
333int TetherController::untetherInterface(const char *interface) {
334    InterfaceCollection::iterator it;
335
336    ALOGD("untetherInterface(%s)", interface);
337
338    for (it = mInterfaces->begin(); it != mInterfaces->end(); ++it) {
339        if (!strcmp(interface, *it)) {
340            free(*it);
341            mInterfaces->erase(it);
342
343            return applyDnsInterfaces();
344        }
345    }
346    errno = ENOENT;
347    return -1;
348}
349
350InterfaceCollection *TetherController::getTetheredInterfaceList() {
351    return mInterfaces;
352}
353