dns_util.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/dns/dns_util.h"
  5. #include <errno.h>
  6. #include <limits.h>
  7. #include <algorithm>
  8. #include <cstring>
  9. #include <string>
  10. #include <unordered_map>
  11. #include <vector>
  12. #include "base/big_endian.h"
  13. #include "base/containers/contains.h"
  14. #include "base/feature_list.h"
  15. #include "base/metrics/field_trial.h"
  16. #include "base/metrics/histogram_macros.h"
  17. #include "base/strings/string_number_conversions.h"
  18. #include "base/strings/string_split.h"
  19. #include "build/build_config.h"
  20. #include "net/base/url_util.h"
  21. #include "net/dns/public/dns_protocol.h"
  22. #include "net/dns/public/doh_provider_entry.h"
  23. #include "net/dns/public/util.h"
  24. #include "net/third_party/uri_template/uri_template.h"
  25. #include "third_party/abseil-cpp/absl/types/optional.h"
  26. #if BUILDFLAG(IS_POSIX)
  27. #include <netinet/in.h>
  28. #include <net/if.h>
  29. #if !BUILDFLAG(IS_ANDROID)
  30. #include <ifaddrs.h>
  31. #endif // !BUILDFLAG(IS_ANDROID)
  32. #endif // BUILDFLAG(IS_POSIX)
  33. #if BUILDFLAG(IS_ANDROID)
  34. #include "net/android/network_library.h"
  35. #endif
  36. namespace net {
  37. namespace {
  38. // Based on DJB's public domain code.
  39. bool DNSDomainFromDot(const base::StringPiece& dotted,
  40. bool is_unrestricted,
  41. std::string* out) {
  42. const char* buf = dotted.data();
  43. size_t n = dotted.size();
  44. char label[dns_protocol::kMaxLabelLength];
  45. size_t labellen = 0; /* <= sizeof label */
  46. char name[dns_protocol::kMaxNameLength];
  47. size_t namelen = 0; /* <= sizeof name */
  48. char ch;
  49. for (;;) {
  50. if (!n)
  51. break;
  52. ch = *buf++;
  53. --n;
  54. if (ch == '.') {
  55. // Don't allow empty labels per http://crbug.com/456391.
  56. if (!labellen)
  57. return false;
  58. if (namelen + labellen + 1 > sizeof name)
  59. return false;
  60. name[namelen++] = static_cast<char>(labellen);
  61. memcpy(name + namelen, label, labellen);
  62. namelen += labellen;
  63. labellen = 0;
  64. continue;
  65. }
  66. if (labellen >= sizeof label)
  67. return false;
  68. if (!is_unrestricted && !IsValidHostLabelCharacter(ch, labellen == 0)) {
  69. return false;
  70. }
  71. label[labellen++] = ch;
  72. }
  73. // Allow empty label at end of name to disable suffix search.
  74. if (labellen) {
  75. if (namelen + labellen + 1 > sizeof name)
  76. return false;
  77. name[namelen++] = static_cast<char>(labellen);
  78. memcpy(name + namelen, label, labellen);
  79. namelen += labellen;
  80. labellen = 0;
  81. }
  82. if (namelen + 1 > sizeof name)
  83. return false;
  84. if (namelen == 0) // Empty names e.g. "", "." are not valid.
  85. return false;
  86. name[namelen++] = 0; // This is the root label (of length 0).
  87. *out = std::string(name, namelen);
  88. return true;
  89. }
  90. DohProviderEntry::List GetDohProviderEntriesFromNameservers(
  91. const std::vector<IPEndPoint>& dns_servers) {
  92. const DohProviderEntry::List& providers = DohProviderEntry::GetList();
  93. DohProviderEntry::List entries;
  94. for (const auto& server : dns_servers) {
  95. for (const auto* entry : providers) {
  96. // DoH servers should only be added once.
  97. if (base::FeatureList::IsEnabled(entry->feature) &&
  98. base::Contains(entry->ip_addresses, server.address()) &&
  99. !base::Contains(entries, entry)) {
  100. entries.push_back(entry);
  101. }
  102. }
  103. }
  104. return entries;
  105. }
  106. } // namespace
  107. bool DNSDomainFromDot(const base::StringPiece& dotted, std::string* out) {
  108. return DNSDomainFromDot(dotted, false /* is_unrestricted */, out);
  109. }
  110. bool DNSDomainFromUnrestrictedDot(const base::StringPiece& dotted,
  111. std::string* out) {
  112. return DNSDomainFromDot(dotted, true /* is_unrestricted */, out);
  113. }
  114. bool IsValidDNSDomain(const base::StringPiece& dotted) {
  115. std::string dns_formatted;
  116. return DNSDomainFromDot(dotted, &dns_formatted);
  117. }
  118. bool IsValidUnrestrictedDNSDomain(const base::StringPiece& dotted) {
  119. std::string dns_formatted;
  120. return DNSDomainFromUnrestrictedDot(dotted, &dns_formatted);
  121. }
  122. bool IsValidHostLabelCharacter(char c, bool is_first_char) {
  123. return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
  124. (c >= '0' && c <= '9') || (!is_first_char && c == '-') || c == '_';
  125. }
  126. absl::optional<std::string> DnsDomainToString(base::StringPiece dns_name,
  127. bool require_complete) {
  128. auto reader = base::BigEndianReader::FromStringPiece(dns_name);
  129. return DnsDomainToString(reader, require_complete);
  130. }
  131. absl::optional<std::string> DnsDomainToString(base::BigEndianReader& reader,
  132. bool require_complete) {
  133. std::string ret;
  134. size_t octets_read = 0;
  135. while (reader.remaining() > 0) {
  136. // DNS name compression not allowed because it does not make sense without
  137. // the context of a full DNS message.
  138. if ((*reader.ptr() & dns_protocol::kLabelMask) ==
  139. dns_protocol::kLabelPointer)
  140. return absl::nullopt;
  141. base::StringPiece label;
  142. if (!reader.ReadU8LengthPrefixed(&label))
  143. return absl::nullopt;
  144. // Final zero-length label not included in size enforcement.
  145. if (label.size() != 0)
  146. octets_read += label.size() + 1;
  147. if (label.size() > dns_protocol::kMaxLabelLength)
  148. return absl::nullopt;
  149. if (octets_read > dns_protocol::kMaxNameLength)
  150. return absl::nullopt;
  151. if (label.size() == 0)
  152. return ret;
  153. if (!ret.empty())
  154. ret.append(".");
  155. ret.append(label.data(), label.size());
  156. }
  157. if (require_complete)
  158. return absl::nullopt;
  159. // If terminating zero-length label was not included in the input, no need to
  160. // recheck against max name length because terminating zero-length label does
  161. // not count against the limit.
  162. return ret;
  163. }
  164. std::string GetURLFromTemplateWithoutParameters(const string& server_template) {
  165. std::string url_string;
  166. std::unordered_map<string, string> parameters;
  167. uri_template::Expand(server_template, parameters, &url_string);
  168. return url_string;
  169. }
  170. namespace {
  171. bool GetTimeDeltaForConnectionTypeFromFieldTrial(
  172. const char* field_trial,
  173. NetworkChangeNotifier::ConnectionType type,
  174. base::TimeDelta* out) {
  175. std::string group = base::FieldTrialList::FindFullName(field_trial);
  176. if (group.empty())
  177. return false;
  178. std::vector<base::StringPiece> group_parts = base::SplitStringPiece(
  179. group, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
  180. if (type < 0)
  181. return false;
  182. size_t type_size = static_cast<size_t>(type);
  183. if (type_size >= group_parts.size())
  184. return false;
  185. int64_t ms;
  186. if (!base::StringToInt64(group_parts[type_size], &ms))
  187. return false;
  188. *out = base::Milliseconds(ms);
  189. return true;
  190. }
  191. } // namespace
  192. base::TimeDelta GetTimeDeltaForConnectionTypeFromFieldTrialOrDefault(
  193. const char* field_trial,
  194. base::TimeDelta default_delta,
  195. NetworkChangeNotifier::ConnectionType type) {
  196. base::TimeDelta out;
  197. if (!GetTimeDeltaForConnectionTypeFromFieldTrial(field_trial, type, &out))
  198. out = default_delta;
  199. return out;
  200. }
  201. std::string CreateNamePointer(uint16_t offset) {
  202. DCHECK_EQ(offset & ~dns_protocol::kOffsetMask, 0);
  203. char buf[2];
  204. base::WriteBigEndian(buf, offset);
  205. buf[0] |= dns_protocol::kLabelPointer;
  206. return std::string(buf, sizeof(buf));
  207. }
  208. uint16_t DnsQueryTypeToQtype(DnsQueryType dns_query_type) {
  209. switch (dns_query_type) {
  210. case DnsQueryType::UNSPECIFIED:
  211. NOTREACHED();
  212. return 0;
  213. case DnsQueryType::A:
  214. return dns_protocol::kTypeA;
  215. case DnsQueryType::AAAA:
  216. return dns_protocol::kTypeAAAA;
  217. case DnsQueryType::TXT:
  218. return dns_protocol::kTypeTXT;
  219. case DnsQueryType::PTR:
  220. return dns_protocol::kTypePTR;
  221. case DnsQueryType::SRV:
  222. return dns_protocol::kTypeSRV;
  223. case DnsQueryType::INTEGRITY:
  224. return dns_protocol::kExperimentalTypeIntegrity;
  225. case DnsQueryType::HTTPS:
  226. case DnsQueryType::HTTPS_EXPERIMENTAL:
  227. return dns_protocol::kTypeHttps;
  228. }
  229. }
  230. DnsQueryType AddressFamilyToDnsQueryType(AddressFamily address_family) {
  231. switch (address_family) {
  232. case ADDRESS_FAMILY_UNSPECIFIED:
  233. return DnsQueryType::UNSPECIFIED;
  234. case ADDRESS_FAMILY_IPV4:
  235. return DnsQueryType::A;
  236. case ADDRESS_FAMILY_IPV6:
  237. return DnsQueryType::AAAA;
  238. default:
  239. NOTREACHED();
  240. return DnsQueryType::UNSPECIFIED;
  241. }
  242. }
  243. std::vector<DnsOverHttpsServerConfig> GetDohUpgradeServersFromDotHostname(
  244. const std::string& dot_server) {
  245. std::vector<DnsOverHttpsServerConfig> doh_servers;
  246. if (dot_server.empty())
  247. return doh_servers;
  248. for (const auto* entry : DohProviderEntry::GetList()) {
  249. if (base::FeatureList::IsEnabled(entry->feature) &&
  250. base::Contains(entry->dns_over_tls_hostnames, dot_server)) {
  251. doh_servers.push_back(entry->doh_server_config);
  252. }
  253. }
  254. return doh_servers;
  255. }
  256. std::vector<DnsOverHttpsServerConfig> GetDohUpgradeServersFromNameservers(
  257. const std::vector<IPEndPoint>& dns_servers) {
  258. const auto entries = GetDohProviderEntriesFromNameservers(dns_servers);
  259. std::vector<DnsOverHttpsServerConfig> doh_servers;
  260. doh_servers.reserve(entries.size());
  261. std::transform(entries.begin(), entries.end(),
  262. std::back_inserter(doh_servers),
  263. [](const auto* entry) { return entry->doh_server_config; });
  264. return doh_servers;
  265. }
  266. std::string GetDohProviderIdForHistogramFromServerConfig(
  267. const DnsOverHttpsServerConfig& doh_server) {
  268. const auto& entries = DohProviderEntry::GetList();
  269. const auto it =
  270. std::find_if(entries.begin(), entries.end(), [&](const auto* entry) {
  271. return entry->doh_server_config == doh_server;
  272. });
  273. return it != entries.end() ? (*it)->provider : "Other";
  274. }
  275. std::string GetDohProviderIdForHistogramFromNameserver(
  276. const IPEndPoint& nameserver) {
  277. const auto entries = GetDohProviderEntriesFromNameservers({nameserver});
  278. return entries.empty() ? "Other" : entries[0]->provider;
  279. }
  280. std::string SecureDnsModeToString(const SecureDnsMode secure_dns_mode) {
  281. switch (secure_dns_mode) {
  282. case SecureDnsMode::kOff:
  283. return "Off";
  284. case SecureDnsMode::kAutomatic:
  285. return "Automatic";
  286. case SecureDnsMode::kSecure:
  287. return "Secure";
  288. }
  289. }
  290. } // namespace net