1 // Copyright 2022 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_DNS_DNS_NAMES_UTIL_H_ 6 #define NET_DNS_DNS_NAMES_UTIL_H_ 7 8 #include <cstdint> 9 #include <optional> 10 #include <string> 11 #include <string_view> 12 #include <vector> 13 14 #include "base/containers/span.h" 15 #include "base/containers/span_reader.h" 16 #include "base/strings/string_util.h" 17 #include "net/base/net_export.h" 18 19 // Various utilities for converting, validating, and comparing DNS names. 20 namespace net::dns_names_util { 21 22 // Returns true iff `dotted` is acceptable to be encoded as a DNS name. That is 23 // that it is non-empty and fits size limitations. Also must match the expected 24 // structure of dot-separated labels, each non-empty and fitting within 25 // additional size limitations, and an optional dot at the end. See RFCs 1035 26 // and 2181. 27 // 28 // No validation is performed for correctness of characters within a label. 29 // As explained by RFC 2181, commonly cited rules for such characters are not 30 // DNS restrictions, but actually restrictions for Internet hostnames. For such 31 // validation, see IsCanonicalizedHostCompliant(). 32 NET_EXPORT_PRIVATE bool IsValidDnsName(std::string_view dotted_form_name); 33 34 // Like IsValidDnsName() but further validates `dotted_form_name` is not an IP 35 // address (with or without surrounding []) or localhost, as such names would 36 // not be suitable for DNS queries or for use as DNS record names or alias 37 // target names. 38 NET_EXPORT_PRIVATE bool IsValidDnsRecordName(std::string_view dotted_form_name); 39 40 // Convert a dotted-form DNS name to network wire format. Returns nullopt if 41 // input is not valid for conversion (equivalent validity can be checked using 42 // IsValidDnsName()). If `require_valid_internet_hostname` is true, also returns 43 // nullopt if input is not a valid internet hostname (equivalent validity can be 44 // checked using net::IsCanonicalizedHostCompliant()). 45 NET_EXPORT_PRIVATE std::optional<std::vector<uint8_t>> DottedNameToNetwork( 46 std::string_view dotted_form_name, 47 bool require_valid_internet_hostname = false); 48 49 // Converts a domain in DNS format to a dotted string. Excludes the dot at the 50 // end. Returns nullopt on malformed input. 51 // 52 // If `require_complete` is true, input will be considered malformed if it does 53 // not contain a terminating zero-length label. If false, assumes the standard 54 // terminating zero-length label at the end if not included in the input. 55 // 56 // DNS name compression (see RFC 1035, section 4.1.4) is disallowed and 57 // considered malformed. To handle a potentially compressed name, in a 58 // DnsResponse object, use DnsRecordParser::ReadName(). 59 NET_EXPORT_PRIVATE std::optional<std::string> NetworkToDottedName( 60 base::SpanReader<const uint8_t>& reader, 61 bool require_complete = false); 62 NET_EXPORT_PRIVATE std::optional<std::string> NetworkToDottedName( 63 base::span<const uint8_t> span, 64 bool require_complete = false); 65 66 // Reads a length-prefixed region: 67 // 1. reads a big-endian length L from the buffer of a size determined by the 68 // function (e.g. ReadU8 reads an 8-bit length); 69 // 2. sets `*out` to a span over the next L many bytes of the buffer (beyond 70 // the end of the bytes encoding the length); and 71 // 3. skips the main reader past this L-byte substring. 72 // 73 // Fails if reading the length L fails, or if the parsed length is greater 74 // than the number of bytes remaining in the input span. 75 // 76 // On failure, leaves the stream at the same position 77 // as before the call. 78 NET_EXPORT_PRIVATE bool ReadU8LengthPrefixed( 79 base::SpanReader<const uint8_t>& reader, 80 base::span<const uint8_t>* out); 81 NET_EXPORT_PRIVATE bool ReadU16LengthPrefixed( 82 base::SpanReader<const uint8_t>& reader, 83 base::span<const uint8_t>* out); 84 85 // Canonicalize `name` as a URL hostname if able. If unable (typically if a name 86 // is not a valid URL hostname), returns `name` without change because such a 87 // name could still be a valid DNS name. 88 NET_EXPORT_PRIVATE std::string UrlCanonicalizeNameIfAble(std::string_view name); 89 90 // std::map-compliant Compare for two domain names. Works for any valid 91 // dotted-format or network-wire-format names. Returns true iff `lhs` is before 92 // `rhs` in strict weak ordering. 93 class NET_EXPORT_PRIVATE DomainNameComparator { 94 public: operator()95 bool operator()(std::string_view lhs, std::string_view rhs) const { 96 // This works for dotted format or network-wire format as long as the names 97 // are valid because valid network-wire names have labels of max 63 bytes 98 // and thus will never have label length prefixes high enough to be 99 // misinterpreted as capital letters ('A' is 65). 100 return base::CompareCaseInsensitiveASCII(lhs, rhs) < 0; 101 } 102 }; 103 104 } // namespace net::dns_names_util 105 106 #endif // NET_DNS_DNS_NAMES_UTIL_H_ 107