GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/resolv_conf_event_handler.cc Lines: 17 45 37.8 %
Date: 2019-02-03 02:48:13 Branches: 15 28 53.6 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System.
3
 */
4
5
#include "resolv_conf_event_handler.h"
6
7
#include <string>
8
#include <vector>
9
10
#include "backoff.h"
11
#include "logging.h"
12
#include "util/string.h"
13
14
namespace {
15
16
/**
17
 * Get the first address of type address_type from the list of addresses
18
 *
19
 * @param address_list List of IP addresses
20
 * @param address_type Type of IP address desired; Can be either 4 or 6
21
 * @param address (out) The first address found
22
 */
23
bool GetFirstAddress(
24
    const ResolvConfEventHandler::AddressList& address_list,
25
    int address_type, std::string* address) {
26
  bool found = false;
27
28
  for (size_t i = 0u; i < address_list.size(); ++i) {
29
    if (address_list[i].first == address_type) {
30
      *address = address_list[i].second;
31
      found = true;
32
      break;
33
    }
34
  }
35
  return found;
36
}
37
38
}  // namespace
39
40
ResolvConfEventHandler::ResolvConfEventHandler(
41
    download::DownloadManager* download_manager,
42
    download::DownloadManager* external_download_manager)
43
    : download_manager_(download_manager),
44
      external_download_manager_(external_download_manager) {}
45
46
ResolvConfEventHandler::~ResolvConfEventHandler() {}
47
48
bool ResolvConfEventHandler::Handle(const std::string& file_path,
49
                                    file_watcher::Event /*event*/,
50
                                    bool* clear_handler) {
51
  AddressList addresses;
52
  GetDnsAddresses(file_path, &addresses);
53
  if (!addresses.empty()) {
54
    SetDnsAddress(download_manager_, addresses);
55
    SetDnsAddress(external_download_manager_, addresses);
56
  }
57
  *clear_handler = false;
58
  return true;
59
}
60
61
/**
62
 * Returns any  nameserver IP addresses from file
63
 *
64
 * Reads a file, line by line. Returns the IP addresses corresponding
65
 * to nameservers (i.e. from lines "nameserver <IP_ADDRESS>")
66
 */
67
4
void ResolvConfEventHandler::GetDnsAddresses(
68
    const std::string& resolv_file, AddressList* addresses) {
69
4
  bool done = false;
70
4
  BackoffThrottle throttle(100, 1000, 5000);
71
4
  while (!done) {
72
4
    FILE* f = std::fopen(resolv_file.c_str(), "r");
73
4
    if (!f) {
74
      LogCvmfs(kLogCvmfs, kLogDebug,
75
               "ResolvConfEventHandler - Could not open: %s",
76
               resolv_file.c_str());
77
      throttle.Throttle();
78
      continue;
79
    }
80
4
    std::string line;
81
4
    while (GetLineFile(f, &line)) {
82
11
      std::vector<std::string> key_val = SplitString(line, ' ');
83

11
      if (key_val.size() == 2 && key_val[0] == "nameserver") {
84
        // We have found a nameserver line
85
7
        if (SplitString(key_val[1], '.').size() == 4) {
86
          // This looks like an IPv4 address
87
3
          addresses->push_back(std::make_pair(4, key_val[1]));
88
4
        } else if (SplitString(key_val[1], ':').size() == 8) {
89
          // This looks like an IPv6 address
90
2
          addresses->push_back(std::make_pair(6, key_val[1]));
91
        }
92
      }
93
    }
94
4
    std::fclose(f);
95
4
    done = true;
96
  }
97
4
}
98
99
void ResolvConfEventHandler::SetDnsAddress(
100
    download::DownloadManager* download_manager,
101
    const AddressList& addresses) {
102
  // Default to IPv4 addresses unless kIpPreferV6 is specified
103
  const int address_type =
104
    download_manager->opt_ip_preference() == dns::kIpPreferV6 ? 6 : 4;
105
106
  std::string new_address;
107
  if (GetFirstAddress(addresses, address_type, &new_address)) {
108
    LogCvmfs(kLogCvmfs, kLogDebug,
109
        "ResolvConfEventhandler - resolv.conf file changed. "
110
        "Setting new DNS address: %s",
111
        new_address.c_str());
112
    download_manager->SetDnsServer(new_address);
113
  }
114
}
115