Name.cpp 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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/Vector.h>
  10. #include <ctype.h>
  11. namespace DNS {
  12. Name::Name(String const& name)
  13. {
  14. if (name.ends_with('.'))
  15. m_name = name.substring(0, name.length() - 1);
  16. else
  17. m_name = name;
  18. }
  19. Name Name::parse(u8 const* data, size_t& offset, size_t max_offset, size_t recursion_level)
  20. {
  21. if (recursion_level > 4)
  22. return {};
  23. StringBuilder builder;
  24. while (true) {
  25. if (offset >= max_offset)
  26. return {};
  27. u8 b = data[offset++];
  28. if (b == '\0') {
  29. // This terminates the name.
  30. return builder.to_string();
  31. } else if ((b & 0xc0) == 0xc0) {
  32. // The two bytes tell us the offset when to continue from.
  33. if (offset >= max_offset)
  34. return {};
  35. size_t dummy = (b & 0x3f) << 8 | data[offset++];
  36. auto rest_of_name = parse(data, dummy, max_offset, recursion_level + 1);
  37. builder.append(rest_of_name.as_string());
  38. return builder.to_string();
  39. } else {
  40. // This is the length of a part.
  41. if (offset + b >= max_offset)
  42. return {};
  43. builder.append((char const*)&data[offset], (size_t)b);
  44. builder.append('.');
  45. offset += b;
  46. }
  47. }
  48. }
  49. size_t Name::serialized_size() const
  50. {
  51. if (m_name.is_empty())
  52. return 1;
  53. return m_name.length() + 2;
  54. }
  55. void Name::randomize_case()
  56. {
  57. StringBuilder builder;
  58. for (char c : m_name) {
  59. // Randomize the 0x20 bit in every ASCII character.
  60. if (isalpha(c)) {
  61. if (get_random_uniform(2))
  62. c |= 0x20;
  63. else
  64. c &= ~0x20;
  65. }
  66. builder.append(c);
  67. }
  68. m_name = builder.to_string();
  69. }
  70. OutputStream& operator<<(OutputStream& stream, Name const& name)
  71. {
  72. auto parts = name.as_string().split_view('.');
  73. for (auto& part : parts) {
  74. stream << (u8)part.length();
  75. stream << part.bytes();
  76. }
  77. stream << '\0';
  78. return stream;
  79. }
  80. unsigned Name::Traits::hash(Name const& name)
  81. {
  82. return CaseInsensitiveStringTraits::hash(name.as_string());
  83. }
  84. bool Name::Traits::equals(Name const& a, Name const& b)
  85. {
  86. return CaseInsensitiveStringTraits::equals(a.as_string(), b.as_string());
  87. }
  88. }