Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2020 Project CHIP Authors 4 : * 5 : * Licensed under the Apache License, Version 2.0 (the "License"); 6 : * you may not use this file except in compliance with the License. 7 : * You may obtain a copy of the License at 8 : * 9 : * http://www.apache.org/licenses/LICENSE-2.0 10 : * 11 : * Unless required by applicable law or agreed to in writing, software 12 : * distributed under the License is distributed on an "AS IS" BASIS, 13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 : * See the License for the specific language governing permissions and 15 : * limitations under the License. 16 : */ 17 : #pragma once 18 : 19 : #include <lib/core/CHIPEncoding.h> 20 : 21 : namespace mdns { 22 : namespace Minimal { 23 : 24 : /** 25 : * Wrapper around a MDNS bit-packed flags in a DNS header as defined in 26 : * RFC 1035 and RFC 6762 27 : * 28 : * | 0| 1 2 3 4| 5| 6| 7| 8| 9| 0| 1| 2 3 4 5 | 29 : * |QR| OPCODE |AA|TC|RD|RA| Z|AD|CD| RCODE | 30 : * 31 : * RFC 6762 states: 32 : * - OPCODE must be 0 on transmission and queries received that are not 0 MUST be ignored 33 : * - RCODE must be 0 on transmission and messages received with non-zero must be silently ignored 34 : * 35 : * - AA (Authoritative Answer) MUST be 0 on transmission, ignored on reception 36 : * - RD (Recursion desired) MUST be 0 on transmission, ignored on reception 37 : * - RA (Recursion available) MUST be 0 on transmission, ignored on reception 38 : * - AD (Authentic data) MUST be 0 on transmission, ignored on reception 39 : * - CD (Checking Disabled) MUST be 0 on transmission, ignored on reception 40 : * 41 : * Accessors are only provided on useful values 42 : */ 43 : class BitPackedFlags 44 : { 45 : public: 46 208 : explicit BitPackedFlags(uint16_t value) : mValue(value) {} 47 : 48 56 : uint16_t RawValue() const { return mValue & kMdnsNonIgnoredMask; } 49 : 50 32 : bool IsQuery() const { return (mValue & kIsResponseMask) == 0; } 51 0 : BitPackedFlags & SetQuery() { return ClearMask(kIsResponseMask); } 52 : 53 64 : bool IsResponse() const { return (mValue & kIsResponseMask) == kIsResponseMask; } 54 110 : BitPackedFlags & SetResponse() { return SetMask(kIsResponseMask); } 55 : 56 : bool IsAuthoritative() const { return (mValue & kAuthoritativeMask) == kAuthoritativeMask; } 57 110 : BitPackedFlags & SetAuthoritative() { return SetMask(kAuthoritativeMask); } 58 : 59 : bool IsTruncated() const { return (mValue & kTruncationMask) != 0; } 60 10 : BitPackedFlags & SetTruncated(bool value) { return value ? SetMask(kTruncationMask) : ClearMask(kTruncationMask); } 61 : 62 : /// Validates that the message does not need to be ignored according to 63 : /// RFC 6762 64 64 : bool IsValidMdns() const { return (mValue & (kOpcodeMask | kReturnCodeMask)) == 0; } 65 : 66 : private: 67 : uint16_t mValue = 0; 68 : 69 0 : inline BitPackedFlags & ClearMask(uint16_t mask) 70 : { 71 0 : mValue &= static_cast<uint16_t>(~mask); 72 0 : return *this; 73 : } 74 : 75 230 : inline BitPackedFlags & SetMask(uint16_t mask) 76 : { 77 230 : mValue |= mask; 78 230 : return *this; 79 : } 80 : 81 : // Mask to limit values to what RFC 6762 consideres useful 82 : // 1111 1110 0000 0000 = FE0F 83 : // TODO(cecille): need to better document this value. Why is the comment different than the value? 84 : static constexpr uint16_t kMdnsNonIgnoredMask = 0x8E08; 85 : static constexpr uint16_t kAuthoritativeMask = 0x0400; 86 : static constexpr uint16_t kIsResponseMask = 0x8000; 87 : static constexpr uint16_t kOpcodeMask = 0x7000; 88 : static constexpr uint16_t kTruncationMask = 0x0200; 89 : static constexpr uint16_t kReturnCodeMask = 0x000F; 90 : }; 91 : 92 : /** 93 : * Allows operations on a DNS header. A DNS Header is defined in RFC 1035 94 : * and looks like this: 95 : * 96 : * | 0| 1 2 3 4| 5| 6| 7| 8| 9| 0| 1| 2 3 4 5 | 97 : * | Message ID | 98 : * |QR| OPCODE |AA|TC|RD|RA| Z|AD|CD| RCODE | 99 : * | Items in QUESTION Section | 100 : * | Items in ANSWER Section | 101 : * | Items in AUTHORITY Section | 102 : * | Items in ADDITIONAL Section | 103 : */ 104 : class ConstHeaderRef 105 : { 106 : public: 107 : static constexpr size_t kSizeBytes = 12; /// size of a DNS header structure 108 193 : ConstHeaderRef(const uint8_t * buffer) : mBuffer(buffer) {} 109 : 110 24 : uint16_t GetMessageId() const { return Get16At(kMessageIdOffset); } 111 : 112 208 : BitPackedFlags GetFlags() const { return BitPackedFlags(Get16At(kFlagsOffset)); } 113 : 114 88 : uint16_t GetQueryCount() const { return Get16At(kQueryCountOffset); } 115 1137 : uint16_t GetAnswerCount() const { return Get16At(kAnswerCountOffset); } 116 541 : uint16_t GetAuthorityCount() const { return Get16At(kAuthorityCountOffset); } 117 513 : uint16_t GetAdditionalCount() const { return Get16At(kAdditionalCountOffset); } 118 : 119 : protected: 120 : const uint8_t * mBuffer; 121 : 122 2435 : inline uint16_t Get16At(size_t offset) const { return chip::Encoding::BigEndian::Get16(mBuffer + offset); } 123 : uint16_t GetRawFlags() const { return Get16At(kFlagsOffset); } 124 : 125 : static constexpr size_t kMessageIdOffset = 0; 126 : static constexpr size_t kFlagsOffset = 2; 127 : static constexpr size_t kQueryCountOffset = 4; 128 : static constexpr size_t kAnswerCountOffset = 6; 129 : static constexpr size_t kAuthorityCountOffset = 8; 130 : static constexpr size_t kAdditionalCountOffset = 10; 131 : }; 132 : 133 : class HeaderRef : public ConstHeaderRef 134 : { 135 : public: 136 129 : HeaderRef(uint8_t * buffer) : ConstHeaderRef(buffer) {} 137 : HeaderRef(const HeaderRef & other) = default; 138 : HeaderRef & operator=(const HeaderRef & other) = default; 139 : 140 56 : HeaderRef & Clear() 141 : { 142 56 : memset(GetWritable(), 0, kSizeBytes); 143 56 : return *this; 144 : } 145 : 146 56 : HeaderRef & SetMessageId(uint16_t value) { return Set16At(kMessageIdOffset, value); } 147 56 : HeaderRef & SetFlags(BitPackedFlags flags) { return Set16At(kFlagsOffset, flags.RawValue()); } 148 0 : HeaderRef & SetQueryCount(uint16_t value) { return Set16At(kQueryCountOffset, value); } 149 832 : HeaderRef & SetAnswerCount(uint16_t value) { return Set16At(kAnswerCountOffset, value); } 150 1 : HeaderRef & SetAuthorityCount(uint16_t value) { return Set16At(kAuthorityCountOffset, value); } 151 25 : HeaderRef & SetAdditionalCount(uint16_t value) { return Set16At(kAdditionalCountOffset, value); } 152 : 153 : private: 154 : /// Returns the internal buffer as writable. Const-cast is correct because 155 : /// the construct took a non-const buffer as well. 156 591 : uint8_t * GetWritable() { return const_cast<uint8_t *>(mBuffer); } 157 : 158 552 : inline HeaderRef & Set16At(size_t offset, uint16_t value) 159 : { 160 552 : chip::Encoding::BigEndian::Put16(GetWritable() + offset, value); 161 552 : return *this; 162 : } 163 : 164 : HeaderRef & SetRawFlags(uint16_t value) { return Set16At(kFlagsOffset, value); } 165 : }; 166 : 167 : } // namespace Minimal 168 : } // namespace mdns