Home | History | Annotate | Download | only in server
      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 
     35 static const char* kClatdPath = "/system/bin/clatd";
     36 
     37 namespace android {
     38 namespace net {
     39 
     40 ClatdController::ClatdController(NetworkController* controller)
     41         : mNetCtrl(controller) {
     42 }
     43 
     44 ClatdController::~ClatdController() {
     45 }
     46 
     47 // Returns the PID of the clatd running on interface |interface|, or 0 if clatd is not running on
     48 // |interface|.
     49 pid_t ClatdController::getClatdPid(char* interface) {
     50     auto it = mClatdPids.find(interface);
     51     return (it == mClatdPids.end() ? 0 : it->second);
     52 }
     53 
     54 int 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 
    119 int 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 
    138 bool 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