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