blob: ab7b6346c1878a76f6cb11b0d9aa106343763b4a [file] [log] [blame]
Peter Qiu326b6cf2015-09-02 11:11:42 -07001//
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//
Peter Qiubf8e36c2014-12-03 22:59:45 -080016
17#include "apmanager/dhcp_server.h"
18
19#include <net/if.h>
20#include <signal.h>
21
Peter Qiubf8e36c2014-12-03 22:59:45 -080022#include <base/strings/stringprintf.h>
23
Peter Qiu58676b62014-12-16 16:47:12 -080024#include "apmanager/daemon.h"
25
Peter Qiubf8e36c2014-12-03 22:59:45 -080026using std::string;
27
28namespace apmanager {
29
30// static.
Peter Qiufc980572015-09-24 10:11:26 -070031#if !defined(__ANDROID__)
Peter Qiubf8e36c2014-12-03 22:59:45 -080032const char DHCPServer::kDnsmasqPath[] = "/usr/sbin/dnsmasq";
Peter Qiu77517302015-01-08 16:22:16 -080033const char DHCPServer::kDnsmasqConfigFilePathFormat[] =
34 "/var/run/apmanager/dnsmasq/dhcpd-%d.conf";
35const char DHCPServer::kDHCPLeasesFilePathFormat[] =
36 "/var/run/apmanager/dnsmasq/dhcpd-%d.leases";
Peter Qiufc980572015-09-24 10:11:26 -070037#else
38const char DHCPServer::kDnsmasqPath[] = "/system/bin/dnsmasq";
39const char DHCPServer::kDnsmasqConfigFilePathFormat[] =
40 "/data/misc/apmanager/dnsmasq/dhcpd-%d.conf";
41const char DHCPServer::kDHCPLeasesFilePathFormat[] =
42 "/data/misc/apmanager/dnsmasq/dhcpd-%d.leases";
Peter Qiu784aa322015-09-29 09:48:03 -070043const char DHCPServer::kDnsmasqPidFilePath[] =
44 "/data/misc/apmanager/dnsmasq/dnsmasq.pid";
Peter Qiufc980572015-09-24 10:11:26 -070045#endif // __ANDROID__
46
Peter Qiubf8e36c2014-12-03 22:59:45 -080047const char DHCPServer::kServerAddressFormat[] = "192.168.%d.254";
48const char DHCPServer::kAddressRangeLowFormat[] = "192.168.%d.1";
49const char DHCPServer::kAddressRangeHighFormat[] = "192.168.%d.128";
50const int DHCPServer::kServerAddressPrefix = 24;
51const int DHCPServer::kTerminationTimeoutSeconds = 2;
52
53DHCPServer::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),
Peter Qiu77517302015-01-08 16:22:16 -080058 rtnl_handler_(shill::RTNLHandler::GetInstance()),
Peter Qiu1dbf9fd2015-01-09 13:36:55 -080059 file_writer_(FileWriter::GetInstance()),
60 process_factory_(ProcessFactory::GetInstance()) {}
Peter Qiubf8e36c2014-12-03 22:59:45 -080061
62DHCPServer::~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
73bool 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();
Peter Qiu77517302015-01-08 16:22:16 -080081 string file_name = base::StringPrintf(kDnsmasqConfigFilePathFormat,
82 server_address_index_);
83 if (!file_writer_->Write(file_name, config_str)) {
Peter Qiubf8e36c2014-12-03 22:59:45 -080084 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
Peter Qiubf8e36c2014-12-03 22:59:45 -0800100 // Start a dnsmasq process.
Peter Qiu1dbf9fd2015-01-09 13:36:55 -0800101 dnsmasq_process_.reset(process_factory_->CreateProcess());
Peter Qiubf8e36c2014-12-03 22:59:45 -0800102 dnsmasq_process_->AddArg(kDnsmasqPath);
103 dnsmasq_process_->AddArg(base::StringPrintf("--conf-file=%s",
Peter Qiu77517302015-01-08 16:22:16 -0800104 file_name.c_str()));
Peter Qiu784aa322015-09-29 09:48:03 -0700105#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__
Peter Qiubf8e36c2014-12-03 22:59:45 -0800111 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
121string 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";
Peter Qiue1ed1cd2014-12-06 16:03:35 -0800134 // 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";
Peter Qiubf8e36c2014-12-03 22:59:45 -0800141 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());
Peter Qiu015a4992015-10-06 13:30:32 -0700144 // 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);
Peter Qiubf8e36c2014-12-03 22:59:45 -0800147 base::StringAppendF(&config, "dhcp-leasefile=%s\n", lease_file_path.c_str());
148 return config;
149}
150
151} // namespace apmanager