1//
2// Copyright (C) 2015 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 "shill/dns_server_proxy.h"
18
19#include <map>
20
21#include <base/bind.h>
22#include <base/strings/stringprintf.h>
23
24#include "shill/logging.h"
25#include "shill/process_manager.h"
26
27using std::string;
28using std::vector;
29
30namespace shill {
31
32namespace {
33const char kDnsmasqPath[] = "/system/bin/dnsmasq";
34const char kDnsmasqPidFilePath[] = "/data/misc/shill/dnsmasq.pid";
35const char kDnsmasqUser[] = "system";
36const char kDnsmasqGroup[] = "system";
37const int kInvalidPID = -1;
38}
39
40DNSServerProxy::DNSServerProxy(const vector<string>& dns_servers)
41    : process_manager_(ProcessManager::GetInstance()),
42      pid_(kInvalidPID),
43      dns_servers_(dns_servers) {}
44
45DNSServerProxy::~DNSServerProxy() {
46  if (pid_ != kInvalidPID) {
47    Stop();
48  }
49}
50
51bool DNSServerProxy::Start() {
52  if (pid_ != kInvalidPID) {
53    LOG(ERROR) << __func__ << ": already started";
54    return false;
55  }
56  // Setup command line arguments for dnsmasq.
57  vector<string> args;
58  args.push_back("--no-hosts");
59  args.push_back("--listen-address=127.0.0.1");
60  args.push_back("--no-resolv");
61  args.push_back("--keep-in-foreground");
62  args.push_back(base::StringPrintf("--user=%s", kDnsmasqUser));
63  args.push_back(base::StringPrintf("--group=%s", kDnsmasqGroup));
64  for (const auto& server : dns_servers_) {
65    args.push_back(base::StringPrintf("--server=%s", server.c_str()));
66  }
67  args.push_back(base::StringPrintf("--pid-file=%s", kDnsmasqPidFilePath));
68  // Start dnsmasq.
69  // TODO(zqiu): start dnsmasq with Minijail when the latter is working on
70  // Android (b/24572800).
71  pid_t pid =
72      process_manager_->StartProcess(
73          FROM_HERE,
74          base::FilePath(kDnsmasqPath),
75          args,
76          std::map<string, string>(),    // No environment variables needed.
77          true,                          // Terminate with parent.
78          base::Bind(&DNSServerProxy::OnProcessExited,
79                     weak_factory_.GetWeakPtr()));
80  if (pid < 0) {
81    return false;
82  }
83
84  pid_ = pid;
85  LOG(INFO) << "Spawned " << kDnsmasqPath << " with pid: " << pid_;
86  return true;
87}
88
89void DNSServerProxy::Stop() {
90  if (pid_ == kInvalidPID) {
91    LOG(ERROR) << __func__ << ": already stopped";
92    return;
93  }
94  process_manager_->StopProcess(pid_);
95}
96
97void DNSServerProxy::OnProcessExited(int exit_status) {
98  CHECK(pid_);
99  if (exit_status != EXIT_SUCCESS) {
100    LOG(WARNING) << "pid " << pid_ << " exit status " << exit_status;
101  }
102  pid_ = kInvalidPID;
103}
104
105}  // namespace shill
106