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 102 : explicit BitPackedFlags(uint16_t value) : mValue(value) {}
47 :
48 50 : uint16_t RawValue() const { return mValue & kMdnsNonIgnoredMask; }
49 :
50 12 : bool IsQuery() const { return (mValue & kIsResponseMask) == 0; }
51 0 : BitPackedFlags & SetQuery() { return ClearMask(kIsResponseMask); }
52 :
53 24 : bool IsResponse() const { return (mValue & kIsResponseMask) == kIsResponseMask; }
54 104 : BitPackedFlags & SetResponse() { return SetMask(kIsResponseMask); }
55 :
56 : bool IsAuthoritative() const { return (mValue & kAuthoritativeMask) == kAuthoritativeMask; }
57 104 : 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 24 : 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 218 : inline BitPackedFlags & SetMask(uint16_t mask)
76 : {
77 218 : mValue |= mask;
78 218 : 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 122 : ConstHeaderRef(const uint8_t * buffer) : mBuffer(buffer) {}
109 :
110 24 : uint16_t GetMessageId() const { return Get16At(kMessageIdOffset); }
111 :
112 102 : BitPackedFlags GetFlags() const { return BitPackedFlags(Get16At(kFlagsOffset)); }
113 :
114 48 : uint16_t GetQueryCount() const { return Get16At(kQueryCountOffset); }
115 677 : uint16_t GetAnswerCount() const { return Get16At(kAnswerCountOffset); }
116 447 : uint16_t GetAuthorityCount() const { return Get16At(kAuthorityCountOffset); }
117 419 : uint16_t GetAdditionalCount() const { return Get16At(kAdditionalCountOffset); }
118 :
119 : protected:
120 : const uint8_t * mBuffer;
121 :
122 1641 : 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 98 : HeaderRef(uint8_t * buffer) : ConstHeaderRef(buffer) {}
137 : HeaderRef(const HeaderRef & other) = default;
138 : HeaderRef & operator=(const HeaderRef & other) = default;
139 :
140 50 : HeaderRef & Clear()
141 : {
142 50 : memset(GetWritable(), 0, kSizeBytes);
143 50 : return *this;
144 : }
145 :
146 50 : HeaderRef & SetMessageId(uint16_t value) { return Set16At(kMessageIdOffset, value); }
147 50 : HeaderRef & SetFlags(BitPackedFlags flags) { return Set16At(kFlagsOffset, flags.RawValue()); }
148 0 : HeaderRef & SetQueryCount(uint16_t value) { return Set16At(kQueryCountOffset, value); }
149 776 : 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 519 : uint8_t * GetWritable() { return const_cast<uint8_t *>(mBuffer); }
157 :
158 486 : inline HeaderRef & Set16At(size_t offset, uint16_t value)
159 : {
160 486 : chip::Encoding::BigEndian::Put16(GetWritable() + offset, value);
161 486 : return *this;
162 : }
163 :
164 : HeaderRef & SetRawFlags(uint16_t value) { return Set16At(kFlagsOffset, value); }
165 : };
166 :
167 : } // namespace Minimal
168 : } // namespace mdns
|