3 * Copyright (c) 2020 Project CHIP Authors
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <core/CHIPEncoding.h>
25 * Wrapper around a MDNS bit-packed flags in a DNS header as defined in
26 * RFC 1035 and RFC 6762
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 |
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
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
41 * Accessors are only provided on useful values
46 explicit BitPackedFlags(uint16_t value) : mValue(value) {}
48 uint16_t RawValue() const { return mValue & kMdnsNonIgnoredMask; }
50 bool IsQuery() const { return (mValue & kIsResponseMask) == 0; }
51 BitPackedFlags & SetQuery() { return ClearMask(kIsResponseMask); }
53 bool IsResponse() const { return (mValue & kIsResponseMask) == kIsResponseMask; }
54 BitPackedFlags & SetResponse() { return SetMask(kIsResponseMask); }
56 bool IsTruncated() const { return (mValue & kTruncationMask) != 0; }
57 BitPackedFlags & SetTruncated(bool value) { return value ? SetMask(kTruncationMask) : ClearMask(kTruncationMask); }
59 /// Validates that the message does not need to be ignored according to
61 bool IsValidMdns() const { return (mValue & (kOpcodeMask | kReturnCodeMask)) == 0; }
66 inline BitPackedFlags & ClearMask(uint16_t mask)
68 mValue &= static_cast<uint16_t>(~mask);
72 inline BitPackedFlags & SetMask(uint16_t mask)
78 // Mask to limit values to what RFC 6762 consideres useful
79 // 1111 1010 0000 0000 = FA0F
80 static constexpr uint16_t kMdnsNonIgnoredMask = 0x8A08;
82 static constexpr uint16_t kIsResponseMask = 0x8000;
83 static constexpr uint16_t kOpcodeMask = 0x7000;
84 static constexpr uint16_t kTruncationMask = 0x0400;
85 static constexpr uint16_t kReturnCodeMask = 0x000F;
89 * Allows operations on a DNS header. A DNS Header is defined in RFC 1035
90 * and looks like this:
92 * | 0| 1 2 3 4| 5| 6| 7| 8| 9| 0| 1| 2 3 4 5 |
94 * |QR| OPCODE |AA|TC|RD|RA| Z|AD|CD| RCODE |
95 * | Items in QUESTION Section |
96 * | Items in ANSWER Section |
97 * | Items in AUTHORITY Section |
98 * | Items in ADDITIONAL Section |
103 static constexpr size_t kSizeBytes = 12; /// size of a DNS header structure
104 ConstHeaderRef(const uint8_t * buffer) : mBuffer(buffer) {}
106 uint16_t GetMessageId() const { return Get16At(kMessageIdOffset); }
108 BitPackedFlags GetFlags() const { return BitPackedFlags(Get16At(kFlagsOffset)); }
110 uint16_t GetQueryCount() const { return Get16At(kQueryCountOffset); }
111 uint16_t GetAnswerCount() const { return Get16At(kAnswerCountOffset); }
112 uint16_t GetAuthorityCount() const { return Get16At(kAuthorityCountOffset); }
113 uint16_t GetAdditionalCount() const { return Get16At(kAdditionalCountOffset); }
116 const uint8_t * mBuffer;
118 inline uint16_t Get16At(size_t offset) const { return chip::Encoding::BigEndian::Get16(mBuffer + offset); }
119 uint16_t GetRawFlags() const { return Get16At(kFlagsOffset); }
121 static constexpr size_t kMessageIdOffset = 0;
122 static constexpr size_t kFlagsOffset = 2;
123 static constexpr size_t kQueryCountOffset = 4;
124 static constexpr size_t kAnswerCountOffset = 6;
125 static constexpr size_t kAuthorityCountOffset = 8;
126 static constexpr size_t kAdditionalCountOffset = 10;
129 class HeaderRef : public ConstHeaderRef
132 HeaderRef(uint8_t * buffer) : ConstHeaderRef(buffer) {}
133 HeaderRef & operator=(const HeaderRef & other) = default;
137 memset(GetWritable(), 0, kSizeBytes);
141 HeaderRef & SetMessageId(uint16_t value) { return Set16At(kMessageIdOffset, value); }
142 HeaderRef & SetFlags(BitPackedFlags flags) { return Set16At(kFlagsOffset, flags.RawValue()); }
143 HeaderRef & SetQueryCount(uint16_t value) { return Set16At(kQueryCountOffset, value); }
144 HeaderRef & SetAnswerCount(uint16_t value) { return Set16At(kAnswerCountOffset, value); }
145 HeaderRef & SetAuthorityCount(uint16_t value) { return Set16At(kAuthorityCountOffset, value); }
146 HeaderRef & SetAdditionalCount(uint16_t value) { return Set16At(kAdditionalCountOffset, value); }
149 /// Returns the internal buffer as writable. Const-cast is correct because
150 /// the construct took a non-const buffer as well.
151 uint8_t * GetWritable() { return const_cast<uint8_t *>(mBuffer); }
153 inline HeaderRef & Set16At(size_t offset, uint16_t value)
155 chip::Encoding::BigEndian::Put16(GetWritable() + offset, value);
159 HeaderRef & SetRawFlags(uint16_t value) { return Set16At(kFlagsOffset, value); }
162 } // namespace Minimal