220 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			220 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * 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 <dns_sd.h>
 | |
| #include <endian.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| #include <chrono>
 | |
| #include <mutex>
 | |
| #include <random>
 | |
| #include <thread>
 | |
| 
 | |
| #include <android-base/logging.h>
 | |
| #include <android-base/properties.h>
 | |
| 
 | |
| 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<std::mutex> 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<char> 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<std::mutex> 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<uint8_t> dist(0, 61);
 | |
|     for (size_t i = 0; i < len; ++i) {
 | |
|         uint8_t val = dist(mt);
 | |
|         if (val < 10) {
 | |
|             ret += static_cast<char>('0' + val);
 | |
|         } else if (val < 36) {
 | |
|             ret += static_cast<char>('A' + (val - 10));
 | |
|         } else {
 | |
|             ret += static_cast<char>('a' + (val - 36));
 | |
|         }
 | |
|     }
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static std::string GenerateDeviceGuid() {
 | |
|     // The format is adb-<serial_no>-<six-random-alphanum>
 | |
|     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<std::mutex> lock(mdns_lock);
 | |
|     return mdns_registered[kADBSecureConnectServiceRefIndex];
 | |
| }
 |