ClatdController.cpp revision 7035f228d17e925116b1b64a7c917b3196ab8818
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#include <map>
17#include <string>
18
19#include <unistd.h>
20#include <errno.h>
21#include <sys/types.h>
22#include <sys/wait.h>
23
24#define LOG_TAG "ClatdController"
25#include <cutils/log.h>
26
27#include <resolv_netid.h>
28
29#include "NetdConstants.h"
30#include "ClatdController.h"
31#include "Fwmark.h"
32#include "NetdConstants.h"
33#include "NetworkController.h"
34
35static const char* kClatdPath = "/system/bin/clatd";
36
37namespace android {
38namespace net {
39
40ClatdController::ClatdController(NetworkController* controller)
41        : mNetCtrl(controller) {
42}
43
44ClatdController::~ClatdController() {
45}
46
47// Returns the PID of the clatd running on interface |interface|, or 0 if clatd is not running on
48// |interface|.
49pid_t ClatdController::getClatdPid(char* interface) {
50    auto it = mClatdPids.find(interface);
51    return (it == mClatdPids.end() ? 0 : it->second);
52}
53
54int ClatdController::startClatd(char* interface) {
55    pid_t pid = getClatdPid(interface);
56
57    if (pid != 0) {
58        ALOGE("clatd pid=%d already started on %s", pid, interface);
59        errno = EBUSY;
60        return -1;
61    }
62
63    // Pass in the interface, a netid to use for DNS lookups, and a fwmark for outgoing packets.
64    unsigned netId = mNetCtrl->getNetworkForInterface(interface);
65    if (netId == NETID_UNSET) {
66        ALOGE("interface %s not assigned to any netId", interface);
67        errno = ENODEV;
68        return -1;
69    }
70
71    char netIdString[UINT32_STRLEN];
72    snprintf(netIdString, sizeof(netIdString), "%u", netId);
73
74    Fwmark fwmark;
75    fwmark.netId = netId;
76    fwmark.explicitlySelected = true;
77    fwmark.protectedFromVpn = true;
78    fwmark.permission = PERMISSION_SYSTEM;
79
80    char fwmarkString[UINT32_HEX_STRLEN];
81    snprintf(fwmarkString, sizeof(fwmarkString), "0x%x", fwmark.intValue);
82
83    ALOGD("starting clatd on %s", interface);
84
85    std::string progname("clatd-");
86    progname += interface;
87
88    if ((pid = fork()) < 0) {
89        ALOGE("fork failed (%s)", strerror(errno));
90        return -1;
91    }
92
93    if (!pid) {
94        char *args[] = {
95            (char *) progname.c_str(),
96            (char *) "-i",
97            interface,
98            (char *) "-n",
99            netIdString,
100            (char *) "-m",
101            fwmarkString,
102            NULL
103        };
104
105        if (execv(kClatdPath, args)) {
106            ALOGE("execv failed (%s)", strerror(errno));
107            _exit(1);
108        }
109        ALOGE("Should never get here!");
110        _exit(1);
111    } else {
112        mClatdPids[interface] = pid;
113        ALOGD("clatd started on %s", interface);
114    }
115
116    return 0;
117}
118
119int ClatdController::stopClatd(char* interface) {
120    pid_t pid = getClatdPid(interface);
121
122    if (pid == 0) {
123        ALOGE("clatd already stopped");
124        return -1;
125    }
126
127    ALOGD("Stopping clatd pid=%d on %s", pid, interface);
128
129    kill(pid, SIGTERM);
130    waitpid(pid, NULL, 0);
131    mClatdPids.erase(interface);
132
133    ALOGD("clatd on %s stopped", interface);
134
135    return 0;
136}
137
138bool ClatdController::isClatdStarted(char* interface) {
139    pid_t waitpid_status;
140    pid_t pid = getClatdPid(interface);
141    if (pid == 0) {
142        return false;
143    }
144    waitpid_status = waitpid(pid, NULL, WNOHANG);
145    if (waitpid_status != 0) {
146        mClatdPids.erase(interface);  // child exited, don't call waitpid on it again
147    }
148    return waitpid_status == 0; // 0 while child is running
149}
150
151}  // namespace net
152}  // namespace android
153