Home | History | Annotate | Download | only in apmanager
      1 //
      2 // Copyright (C) 2014 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 "apmanager/dhcp_server.h"
     18 
     19 #include <net/if.h>
     20 #include <signal.h>
     21 
     22 #include <base/strings/stringprintf.h>
     23 
     24 #include "apmanager/daemon.h"
     25 
     26 using std::string;
     27 
     28 namespace apmanager {
     29 
     30 // static.
     31 #if !defined(__ANDROID__)
     32 const char DHCPServer::kDnsmasqPath[] = "/usr/sbin/dnsmasq";
     33 const char DHCPServer::kDnsmasqConfigFilePathFormat[] =
     34     "/var/run/apmanager/dnsmasq/dhcpd-%d.conf";
     35 const char DHCPServer::kDHCPLeasesFilePathFormat[] =
     36     "/var/run/apmanager/dnsmasq/dhcpd-%d.leases";
     37 #else
     38 const char DHCPServer::kDnsmasqPath[] = "/system/bin/dnsmasq";
     39 const char DHCPServer::kDnsmasqConfigFilePathFormat[] =
     40     "/data/misc/apmanager/dnsmasq/dhcpd-%d.conf";
     41 const char DHCPServer::kDHCPLeasesFilePathFormat[] =
     42     "/data/misc/apmanager/dnsmasq/dhcpd-%d.leases";
     43 const char DHCPServer::kDnsmasqPidFilePath[] =
     44     "/data/misc/apmanager/dnsmasq/dnsmasq.pid";
     45 #endif  // __ANDROID__
     46 
     47 const char DHCPServer::kServerAddressFormat[] = "192.168.%d.254";
     48 const char DHCPServer::kAddressRangeLowFormat[] = "192.168.%d.1";
     49 const char DHCPServer::kAddressRangeHighFormat[] = "192.168.%d.128";
     50 const int DHCPServer::kServerAddressPrefix = 24;
     51 const int DHCPServer::kTerminationTimeoutSeconds = 2;
     52 
     53 DHCPServer::DHCPServer(uint16_t server_address_index,
     54                        const string& interface_name)
     55     : server_address_index_(server_address_index),
     56       interface_name_(interface_name),
     57       server_address_(shill::IPAddress::kFamilyIPv4),
     58       rtnl_handler_(shill::RTNLHandler::GetInstance()),
     59       file_writer_(FileWriter::GetInstance()),
     60       process_factory_(ProcessFactory::GetInstance()) {}
     61 
     62 DHCPServer::~DHCPServer() {
     63   if (dnsmasq_process_) {
     64     // The destructor of the Process will send a SIGKILL signal if it is not
     65     // already terminated.
     66     dnsmasq_process_->Kill(SIGTERM, kTerminationTimeoutSeconds);
     67     dnsmasq_process_.reset();
     68     rtnl_handler_->RemoveInterfaceAddress(
     69         rtnl_handler_->GetInterfaceIndex(interface_name_), server_address_);
     70   }
     71 }
     72 
     73 bool DHCPServer::Start() {
     74   if (dnsmasq_process_) {
     75     LOG(ERROR) << "DHCP Server already running";
     76     return false;
     77   }
     78 
     79   // Generate dnsmasq config file.
     80   string config_str = GenerateConfigFile();
     81   string file_name = base::StringPrintf(kDnsmasqConfigFilePathFormat,
     82                                         server_address_index_);
     83   if (!file_writer_->Write(file_name, config_str)) {
     84     LOG(ERROR) << "Failed to write configuration to a file";
     85     return false;
     86   }
     87 
     88   // Setup local server address and bring up the interface in case it is down.
     89   server_address_.SetAddressFromString(
     90       base::StringPrintf(kServerAddressFormat, server_address_index_));
     91   server_address_.set_prefix(kServerAddressPrefix);
     92   int interface_index = rtnl_handler_->GetInterfaceIndex(interface_name_);
     93   rtnl_handler_->AddInterfaceAddress(
     94       interface_index,
     95       server_address_,
     96       server_address_.GetDefaultBroadcast(),
     97       shill::IPAddress(shill::IPAddress::kFamilyIPv4));
     98   rtnl_handler_->SetInterfaceFlags(interface_index, IFF_UP, IFF_UP);
     99 
    100   // Start a dnsmasq process.
    101   dnsmasq_process_.reset(process_factory_->CreateProcess());
    102   dnsmasq_process_->AddArg(kDnsmasqPath);
    103   dnsmasq_process_->AddArg(base::StringPrintf("--conf-file=%s",
    104                                               file_name.c_str()));
    105 #if defined(__ANDROID__)
    106   // dnsmasq normally creates a pid file in /var/run/dnsmasq.pid. Overwrite
    107   // this file path for Android.
    108   dnsmasq_process_->AddArg(
    109       base::StringPrintf("--pid-file=%s", kDnsmasqPidFilePath));
    110 #endif  // __ANDROID__
    111   if (!dnsmasq_process_->Start()) {
    112     rtnl_handler_->RemoveInterfaceAddress(interface_index, server_address_);
    113     dnsmasq_process_.reset();
    114     LOG(ERROR) << "Failed to start dnsmasq process";
    115     return false;
    116   }
    117 
    118   return true;
    119 }
    120 
    121 string DHCPServer::GenerateConfigFile() {
    122   string server_address = base::StringPrintf(kServerAddressFormat,
    123                                              server_address_index_);
    124   string address_low = base::StringPrintf(kAddressRangeLowFormat,
    125                                           server_address_index_);
    126   string address_high = base::StringPrintf(kAddressRangeHighFormat,
    127                                            server_address_index_);
    128   string lease_file_path = base::StringPrintf(kDHCPLeasesFilePathFormat,
    129                                               server_address_index_);
    130   string config;
    131   config += "port=0\n";
    132   config += "bind-interfaces\n";
    133   config += "log-dhcp\n";
    134   // By default, dnsmasq process will spawn off another process to run the
    135   // dnsmasq task in the "background" and exit the current process immediately.
    136   // This means the daemon would not have any knowledge of the background
    137   // dnsmasq process, and it will continue to run even after the AP service is
    138   // terminated. Configure dnsmasq to run in "foreground" so no extra process
    139   // will be spawned.
    140   config += "keep-in-foreground\n";
    141   base::StringAppendF(
    142       &config, "dhcp-range=%s,%s\n", address_low.c_str(), address_high.c_str());
    143   base::StringAppendF(&config, "interface=%s\n", interface_name_.c_str());
    144   // Explicitly set the user to apmanager. If not set, dnsmasq will default to
    145   // run as "nobody".
    146   base::StringAppendF(&config, "user=%s\n", Daemon::kAPManagerUserName);
    147   base::StringAppendF(&config, "dhcp-leasefile=%s\n", lease_file_path.c_str());
    148   return config;
    149 }
    150 
    151 }  // namespace apmanager
    152