1 // 2 // Copyright (C) 2012 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 <errno.h> 18 #include <stdio.h> 19 #include <time.h> 20 #include <unistd.h> 21 22 #include <string> 23 #include <vector> 24 25 #include <base/bind.h> 26 #include <base/command_line.h> 27 #include <base/files/file_path.h> 28 #include <base/strings/string_number_conversions.h> 29 #include <base/strings/string_split.h> 30 #include <brillo/minijail/minijail.h> 31 #include <brillo/syslog_logging.h> 32 33 #include "shill/daemon_task.h" 34 #include "shill/error.h" 35 #include "shill/logging.h" 36 #include "shill/shill_config.h" 37 #include "shill/shill_daemon.h" 38 #include "shill/technology.h" 39 40 using base::FilePath; 41 using std::string; 42 using std::vector; 43 44 namespace switches { 45 46 // Don't daemon()ize; run in foreground. 47 static const char kForeground[] = "foreground"; 48 // Don't attempt to manage these devices. 49 static const char kDeviceBlackList[] = "device-black-list"; 50 // Manage only these devices. 51 static const char kDeviceWhiteList[] = "device-white-list"; 52 // Ignore Ethernet-like devices that don't have any driver information. 53 static const char kIgnoreUnknownEthernet[] = "ignore-unknown-ethernet"; 54 // Technologies to enable for portal check at startup. 55 static const char kPortalList[] = "portal-list"; 56 // When in passive mode, Shill will not manage any devices by default. 57 // Remote service can instruct Shill to manage/unmanage devices through 58 // org.chromium.flimflam.Manager's ClaimInterface/ReleaseInterface APIs. 59 static const char kPassiveMode[] = "passive-mode"; 60 // Default priority order of the technologies. 61 static const char kTechnologyOrder[] = "default-technology-order"; 62 // Comma-separated list of DNS servers to prepend to the resolver list. 63 static const char kPrependDNSServers[] = "prepend-dns-servers"; 64 // The minimum MTU value that will be respected in DHCP responses. 65 static const char kMinimumMTU[] = "minimum-mtu"; 66 // Accept hostname from the DHCP server for the specified devices. 67 // eg. eth0 or eth* 68 static const char kAcceptHostnameFrom[] = "accept-hostname-from"; 69 #ifndef DISABLE_DHCPV6 70 // List of devices to enable DHCPv6. 71 static const char kDhcpv6EnabledDevices[] = "dhcpv6-enabled-devices"; 72 #endif // DISABLE_DHCPV6 73 // Flag that causes shill to show the help message and exit. 74 static const char kHelp[] = "help"; 75 76 // The help message shown if help flag is passed to the program. 77 static const char kHelpMessage[] = "\n" 78 "Available Switches: \n" 79 " --foreground\n" 80 " Don\'t daemon()ize; run in foreground.\n" 81 " --device-black-list=device1,device2\n" 82 " Do not manage devices named device1 or device2\n" 83 " --device-white-list=device1,device2\n" 84 " Manage only devices named device1 and device2\n" 85 " --ignore-unknown-ethernet\n" 86 " Ignore Ethernet-like devices that do not report a driver\n" 87 " --log-level=N\n" 88 " Logging level:\n" 89 " 0 = LOG(INFO), 1 = LOG(WARNING), 2 = LOG(ERROR),\n" 90 " -1 = SLOG(..., 1), -2 = SLOG(..., 2), etc.\n" 91 " --log-scopes=\"*scope1+scope2\".\n" 92 " Scopes to enable for SLOG()-based logging.\n" 93 " --portal-list=technology1,technology2\n" 94 " Specify technologies to perform portal detection on at startup.\n" 95 " --passive-mode\n" 96 " Do not manage any devices by default\n" 97 " --default-technology-order=technology1,technology2\n" 98 " Specify the default priority order of the technologies.\n" 99 " --prepend-dns-servers=server1,server2,...\n" 100 " Prepend the provided DNS servers to the resolver list.\n" 101 " --accept-hostname-from=eth0 or --accept-hostname-from=eth*\n" 102 " Accept a hostname from the DHCP server for the matching devices.\n" 103 #ifndef DISABLE_DHCPV6 104 " --dhcpv6-enabled-devices=device1,device2\n" 105 " Enable DHCPv6 for devices named device1 and device2\n" 106 #endif // DISABLE_DHCPV6 107 " --minimum-mtu=mtu\n" 108 " Set the minimum value to respect as the MTU from DHCP responses.\n"; 109 } // namespace switches 110 111 namespace { 112 113 #if !defined(__ANDROID__) 114 const char* kLoggerCommand = "/usr/bin/logger"; 115 const char* kLoggerUser = "syslog"; 116 #endif // __ANDROID__ 117 118 const char* kDefaultTechnologyOrder = "vpn,ethernet,wifi,wimax,cellular"; 119 120 } // namespace 121 122 // Always logs to the syslog and logs to stderr if 123 // we are running in the foreground. 124 void SetupLogging(bool foreground, const char* daemon_name) { 125 int log_flags = 0; 126 log_flags |= brillo::kLogToSyslog; 127 log_flags |= brillo::kLogHeader; 128 if (foreground) { 129 log_flags |= brillo::kLogToStderr; 130 } 131 brillo::InitLog(log_flags); 132 133 #if !defined(__ANDROID__) 134 // Logger utility doesn't exist on Android, so do not run it on Android. 135 // TODO(zqiu): add support to redirect stderr logs from child processes 136 // to Android logging facility. 137 if (!foreground) { 138 vector<char*> logger_command_line; 139 int logger_stdin_fd; 140 logger_command_line.push_back(const_cast<char*>(kLoggerCommand)); 141 logger_command_line.push_back(const_cast<char*>("--priority")); 142 logger_command_line.push_back(const_cast<char*>("daemon.err")); 143 logger_command_line.push_back(const_cast<char*>("--tag")); 144 logger_command_line.push_back(const_cast<char*>(daemon_name)); 145 logger_command_line.push_back(nullptr); 146 147 brillo::Minijail* minijail = brillo::Minijail::GetInstance(); 148 struct minijail* jail = minijail->New(); 149 minijail->DropRoot(jail, kLoggerUser, kLoggerUser); 150 151 if (!minijail->RunPipeAndDestroy(jail, logger_command_line, nullptr, 152 &logger_stdin_fd)) { 153 LOG(ERROR) << "Unable to spawn logger. " 154 << "Writes to stderr will be discarded."; 155 return; 156 } 157 158 // Note that we don't set O_CLOEXEC here. This means that stderr 159 // from any child processes will, by default, be logged to syslog. 160 if (dup2(logger_stdin_fd, fileno(stderr)) != fileno(stderr)) { 161 PLOG(ERROR) << "Failed to redirect stderr to syslog"; 162 } 163 close(logger_stdin_fd); 164 } 165 #endif // __ANDROID__ 166 } 167 168 void OnStartup(const char *daemon_name, base::CommandLine* cl) { 169 SetupLogging(cl->HasSwitch(switches::kForeground), daemon_name); 170 shill::SetLogLevelFromCommandLine(cl); 171 } 172 173 int main(int argc, char** argv) { 174 base::CommandLine::Init(argc, argv); 175 base::CommandLine* cl = base::CommandLine::ForCurrentProcess(); 176 177 if (cl->HasSwitch(switches::kHelp)) { 178 LOG(INFO) << switches::kHelpMessage; 179 return 0; 180 } 181 182 shill::DaemonTask::Settings settings; 183 if (cl->HasSwitch(switches::kTechnologyOrder)) { 184 shill::Error error; 185 string order_flag = cl->GetSwitchValueASCII( 186 switches::kTechnologyOrder); 187 vector<shill::Technology::Identifier> test_order_vector; 188 if (shill::Technology::GetTechnologyVectorFromString( 189 order_flag, &test_order_vector, &error)) { 190 settings.default_technology_order = order_flag; 191 } else { 192 LOG(ERROR) << "Invalid default technology order: [" << order_flag 193 << "] Error: " << error.message(); 194 } 195 } 196 if (settings.default_technology_order.empty()) { 197 settings.default_technology_order = kDefaultTechnologyOrder; 198 } 199 200 if (cl->HasSwitch(switches::kDeviceBlackList)) { 201 settings.device_blacklist = base::SplitString( 202 cl->GetSwitchValueASCII(switches::kDeviceBlackList), ",", 203 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 204 } 205 206 if (cl->HasSwitch(switches::kDeviceWhiteList)) { 207 settings.device_whitelist = base::SplitString( 208 cl->GetSwitchValueASCII(switches::kDeviceWhiteList), ",", 209 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 210 } 211 212 settings.ignore_unknown_ethernet = 213 cl->HasSwitch(switches::kIgnoreUnknownEthernet); 214 215 if (cl->HasSwitch(switches::kPortalList)) { 216 settings.use_portal_list = true; 217 settings.portal_list = cl->GetSwitchValueASCII(switches::kPortalList); 218 } 219 220 settings.passive_mode = cl->HasSwitch(switches::kPassiveMode); 221 222 if (cl->HasSwitch(switches::kPrependDNSServers)) { 223 settings.prepend_dns_servers = 224 cl->GetSwitchValueASCII(switches::kPrependDNSServers); 225 } 226 227 if (cl->HasSwitch(switches::kMinimumMTU)) { 228 int mtu; 229 std::string value = cl->GetSwitchValueASCII(switches::kMinimumMTU); 230 if (!base::StringToInt(value, &mtu)) { 231 LOG(FATAL) << "Could not convert '" << value << "' to integer."; 232 } 233 settings.minimum_mtu = mtu; 234 } 235 236 if (cl->HasSwitch(switches::kAcceptHostnameFrom)) { 237 settings.accept_hostname_from = 238 cl->GetSwitchValueASCII(switches::kAcceptHostnameFrom); 239 } 240 241 #ifndef DISABLE_DHCPV6 242 if (cl->HasSwitch(switches::kDhcpv6EnabledDevices)) { 243 settings.dhcpv6_enabled_devices = base::SplitString( 244 cl->GetSwitchValueASCII(switches::kDhcpv6EnabledDevices), ",", 245 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 246 } 247 #endif // DISABLE_DHCPV6 248 249 shill::Config config; 250 251 shill::ShillDaemon daemon(base::Bind(&OnStartup, argv[0], cl), settings, 252 &config); 253 daemon.Run(); 254 255 LOG(INFO) << "Process exiting."; 256 257 return 0; 258 } 259