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