Name.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021, Sergey Bugaev <bugaevc@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include "Name.h"
  8. #include <AK/Random.h>
  9. #include <AK/Stream.h>
  10. #include <AK/Vector.h>
  11. #include <ctype.h>
  12. namespace DNS {
  13. Name::Name(ByteString const& name)
  14. {
  15. if (name.ends_with('.'))
  16. m_name = name.substring(0, name.length() - 1);
  17. else
  18. m_name = name;
  19. }
  20. ErrorOr<Name> Name::parse(ReadonlyBytes data, size_t& offset, size_t recursion_level)
  21. {
  22. static constexpr size_t MAX_LABEL_SIZE = 63;
  23. static constexpr size_t MAX_NAME_SIZE = 253;
  24. if (recursion_level > 4)
  25. return Name {};
  26. StringBuilder builder;
  27. while (true) {
  28. if (offset >= data.size())
  29. return Error::from_string_literal("Unexpected EOF when parsing name");
  30. u8 b = data[offset++];
  31. if (b == '\0') {
  32. if (builder.length() > MAX_NAME_SIZE)
  33. return Error::from_string_literal("Domain name exceeds maximum allowed length");
  34. // This terminates the name.
  35. return builder.to_byte_string();
  36. } else if ((b & 0xc0) == 0xc0) {
  37. // The two bytes tell us the offset when to continue from.
  38. if (offset >= data.size())
  39. return Error::from_string_literal("Unexpected EOF when parsing name");
  40. size_t dummy = (b & 0x3f) << 8 | data[offset++];
  41. auto rest_of_name = TRY(parse(data, dummy, recursion_level + 1));
  42. builder.append(rest_of_name.as_string());
  43. if (builder.length() > MAX_NAME_SIZE)
  44. return Error::from_string_literal("Domain name exceeds maximum allowed length");
  45. return builder.to_byte_string();
  46. } else {
  47. // This is the length of a part.
  48. if (offset + b >= data.size())
  49. return Error::from_string_literal("Unexpected EOF when parsing name");
  50. if (b > MAX_LABEL_SIZE)
  51. return Error::from_string_literal("DNS label exceeds maximum allowed length");
  52. builder.append({ data.offset_pointer(offset), b });
  53. builder.append('.');
  54. if (builder.length() > MAX_NAME_SIZE)
  55. return Error::from_string_literal("Domain name exceeds maximum allowed length");
  56. offset += b;
  57. }
  58. }
  59. }
  60. size_t Name::serialized_size() const
  61. {
  62. if (m_name.is_empty())
  63. return 1;
  64. return m_name.length() + 2;
  65. }
  66. void Name::randomize_case()
  67. {
  68. StringBuilder builder;
  69. for (char c : m_name) {
  70. // Randomize the 0x20 bit in every ASCII character.
  71. if (isalpha(c)) {
  72. if (get_random_uniform(2))
  73. c |= 0x20;
  74. else
  75. c &= ~0x20;
  76. }
  77. builder.append(c);
  78. }
  79. m_name = builder.to_byte_string();
  80. }
  81. ErrorOr<void> Name::write_to_stream(Stream& stream) const
  82. {
  83. auto parts = as_string().split_view('.');
  84. for (auto& part : parts) {
  85. TRY(stream.write_value<u8>(part.length()));
  86. TRY(stream.write_until_depleted(part.bytes()));
  87. }
  88. TRY(stream.write_value('\0'));
  89. return {};
  90. }
  91. unsigned Name::Traits::hash(Name const& name)
  92. {
  93. return CaseInsensitiveStringTraits::hash(name.as_string());
  94. }
  95. bool Name::Traits::equals(Name const& a, Name const& b)
  96. {
  97. return CaseInsensitiveStringTraits::equals(a.as_string(), b.as_string());
  98. }
  99. }