/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mdns.h" #include "adb_mdns.h" #include "sysdeps.h" #include #include #include #include #include #include #include #include #include using namespace std::chrono_literals; static std::mutex& mdns_lock = *new std::mutex(); static int port; static DNSServiceRef mdns_refs[kNumADBDNSServices]; static bool mdns_registered[kNumADBDNSServices]; void start_mdnsd() { if (android::base::GetProperty("init.svc.mdnsd", "") == "running") { return; } android::base::SetProperty("ctl.start", "mdnsd"); if (! android::base::WaitForProperty("init.svc.mdnsd", "running", 5s)) { LOG(ERROR) << "Could not start mdnsd."; } } static void mdns_callback(DNSServiceRef /*ref*/, DNSServiceFlags /*flags*/, DNSServiceErrorType errorCode, const char* /*name*/, const char* /*regtype*/, const char* /*domain*/, void* /*context*/) { if (errorCode != kDNSServiceErr_NoError) { LOG(ERROR) << "Encountered mDNS registration error (" << errorCode << ")."; } } static void register_mdns_service(int index, int port, const std::string service_name) { std::lock_guard lock(mdns_lock); // https://tools.ietf.org/html/rfc6763 // """ // The format of the data within a DNS TXT record is one or more // strings, packed together in memory without any intervening gaps or // padding bytes for word alignment. // // The format of each constituent string within the DNS TXT record is a // single length byte, followed by 0-255 bytes of text data. // """ // // Therefore: // 1. Begin with the string length // 2. No null termination std::vector txtRecord; if (kADBDNSServiceTxtRecords[index]) { size_t txtRecordStringLength = strlen(kADBDNSServiceTxtRecords[index]); txtRecord.resize(1 + // length byte txtRecordStringLength // string bytes ); txtRecord[0] = (char)txtRecordStringLength; memcpy(txtRecord.data() + 1, kADBDNSServiceTxtRecords[index], txtRecordStringLength); } auto error = DNSServiceRegister( &mdns_refs[index], 0, 0, service_name.c_str(), kADBDNSServices[index], nullptr, nullptr, htobe16((uint16_t)port), (uint16_t)txtRecord.size(), txtRecord.empty() ? nullptr : txtRecord.data(), mdns_callback, nullptr); if (error != kDNSServiceErr_NoError) { LOG(ERROR) << "Could not register mDNS service " << kADBDNSServices[index] << ", error (" << error << ")."; mdns_registered[index] = false; } mdns_registered[index] = true; LOG(INFO) << "adbd mDNS service " << kADBDNSServices[index] << " registered: " << mdns_registered[index]; } static void unregister_mdns_service(int index) { std::lock_guard lock(mdns_lock); if (mdns_registered[index]) { DNSServiceRefDeallocate(mdns_refs[index]); } } static void register_base_mdns_transport() { std::string hostname = "adb-"; hostname += android::base::GetProperty("ro.serialno", "unidentified"); register_mdns_service(kADBTransportServiceRefIndex, port, hostname); } static void setup_mdns_thread() { start_mdnsd(); // We will now only set up the normal transport mDNS service // instead of registering all the adb secure mDNS services // in the beginning. This is to provide more privacy/security. register_base_mdns_transport(); } // This also tears down any adb secure mDNS services, if they exist. static void teardown_mdns() { for (int i = 0; i < kNumADBDNSServices; ++i) { unregister_mdns_service(i); } } static std::string RandomAlphaNumString(size_t len) { std::string ret; std::random_device rd; std::mt19937 mt(rd()); // Generate values starting with zero and then up to enough to cover numeric // digits, small letters and capital letters (26 each). std::uniform_int_distribution dist(0, 61); for (size_t i = 0; i < len; ++i) { uint8_t val = dist(mt); if (val < 10) { ret += static_cast('0' + val); } else if (val < 36) { ret += static_cast('A' + (val - 10)); } else { ret += static_cast('a' + (val - 36)); } } return ret; } static std::string GenerateDeviceGuid() { // The format is adb-- std::string guid = "adb-"; std::string serial = android::base::GetProperty("ro.serialno", ""); if (serial.empty()) { // Generate 16-bytes of random alphanum string serial = RandomAlphaNumString(16); } guid += serial + '-'; // Random six-char suffix guid += RandomAlphaNumString(6); return guid; } static std::string ReadDeviceGuid() { std::string guid = android::base::GetProperty("persist.adb.wifi.guid", ""); if (guid.empty()) { guid = GenerateDeviceGuid(); CHECK(!guid.empty()); android::base::SetProperty("persist.adb.wifi.guid", guid); } return guid; } // Public interface///////////////////////////////////////////////////////////// void setup_mdns(int port_in) { // Make sure the adb wifi guid is generated. std::string guid = ReadDeviceGuid(); CHECK(!guid.empty()); port = port_in; std::thread(setup_mdns_thread).detach(); // TODO: Make this more robust against a hard kill. atexit(teardown_mdns); } void register_adb_secure_connect_service(int port) { std::thread([port]() { auto service_name = ReadDeviceGuid(); if (service_name.empty()) { return; } LOG(INFO) << "Registering secure_connect service (" << service_name << ")"; register_mdns_service(kADBSecureConnectServiceRefIndex, port, service_name); }).detach(); } void unregister_adb_secure_connect_service() { std::thread([]() { unregister_mdns_service(kADBSecureConnectServiceRefIndex); }).detach(); } bool is_adb_secure_connect_service_registered() { std::lock_guard lock(mdns_lock); return mdns_registered[kADBSecureConnectServiceRefIndex]; }