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