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