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 :
18 : #include "Parser.h"
19 :
20 : #include "Query.h"
21 :
22 : #include <stdio.h>
23 :
24 : namespace mdns {
25 : namespace Minimal {
26 :
27 56 : bool QueryData::Parse(const BytesRange & validData, const uint8_t ** start)
28 : {
29 : // Structure is:
30 : // QNAME
31 : // TYPE
32 : // CLASS (plus a flag for unicast)
33 :
34 56 : if (!validData.Contains(*start))
35 : {
36 0 : return false;
37 : }
38 :
39 56 : const uint8_t * nameEnd = nullptr;
40 : {
41 56 : SerializedQNameIterator it(validData, *start);
42 56 : nameEnd = it.FindDataEnd();
43 : }
44 56 : if (nameEnd == nullptr)
45 : {
46 0 : return false;
47 : }
48 :
49 56 : if (!validData.Contains(nameEnd + 3))
50 : {
51 0 : return false;
52 : }
53 :
54 : // TODO: should there be checks for valid mType/class?
55 :
56 56 : mType = static_cast<QType>(chip::Encoding::BigEndian::Read16(nameEnd));
57 :
58 56 : uint16_t klass = chip::Encoding::BigEndian::Read16(nameEnd);
59 :
60 56 : mAnswerViaUnicast = (klass & kQClassUnicastAnswerFlag) != 0;
61 56 : mClass = static_cast<QClass>(klass & ~kQClassUnicastAnswerFlag);
62 56 : mNameIterator = SerializedQNameIterator(validData, *start);
63 :
64 56 : *start = nameEnd;
65 :
66 56 : return true;
67 : }
68 :
69 32 : bool QueryData::Append(HeaderRef & hdr, RecordWriter & out) const
70 : {
71 32 : if ((hdr.GetAdditionalCount() != 0) || (hdr.GetAnswerCount() != 0) || (hdr.GetAuthorityCount() != 0))
72 : {
73 0 : return false;
74 : }
75 :
76 32 : out.WriteQName(GetName())
77 32 : .Put16(static_cast<uint16_t>(mType))
78 32 : .Put16(static_cast<uint16_t>(static_cast<uint16_t>(mClass) | (mAnswerViaUnicast ? kQClassUnicastAnswerFlag : 0)));
79 :
80 32 : if (!out.Fit())
81 : {
82 0 : return false;
83 : }
84 :
85 32 : hdr.SetQueryCount(static_cast<uint16_t>(hdr.GetQueryCount() + 1));
86 32 : return true;
87 : }
88 :
89 328 : bool ResourceData::Parse(const BytesRange & validData, const uint8_t ** start)
90 : {
91 : // Structure is:
92 : // QNAME
93 : // TYPE (16 bit)
94 : // CLASS (16 bit)
95 : // TTL (32 bit)
96 : // RDLENGTH (16 bit)
97 : // <DATA> (RDLENGTH bytes)
98 328 : if (!validData.Contains(*start))
99 : {
100 0 : return false;
101 : }
102 :
103 328 : const uint8_t * nameEnd = nullptr;
104 :
105 : {
106 328 : SerializedQNameIterator it(validData, *start);
107 328 : nameEnd = it.FindDataEnd();
108 : }
109 328 : if (nameEnd == nullptr)
110 : {
111 0 : return false;
112 : }
113 :
114 : // need 3*u16 + u32
115 328 : if (!validData.Contains(nameEnd + 9))
116 : {
117 0 : return false;
118 : }
119 :
120 328 : mType = static_cast<QType>(chip::Encoding::BigEndian::Read16(nameEnd));
121 328 : mClass = static_cast<QClass>(chip::Encoding::BigEndian::Read16(nameEnd));
122 328 : mTtl = chip::Encoding::BigEndian::Read32(nameEnd);
123 :
124 328 : uint16_t dataLen = chip::Encoding::BigEndian::Read16(nameEnd); // resource data
125 :
126 328 : if (!validData.Contains(nameEnd + dataLen - 1))
127 : {
128 0 : return false; // no space for RDATA
129 : }
130 328 : mData = BytesRange(nameEnd, nameEnd + dataLen);
131 :
132 328 : mNameIterator = SerializedQNameIterator(validData, *start);
133 :
134 328 : *start = nameEnd + dataLen;
135 :
136 328 : return true;
137 : }
138 :
139 80 : bool ParsePacket(const BytesRange & packetData, ParserDelegate * delegate)
140 : {
141 80 : if (packetData.Size() < static_cast<ptrdiff_t>(HeaderRef::kSizeBytes))
142 : {
143 0 : return false;
144 : }
145 :
146 : // header is used as const, so cast is safe
147 80 : ConstHeaderRef header(packetData.Start());
148 :
149 80 : if (!header.GetFlags().IsValidMdns())
150 : {
151 0 : return false;
152 : }
153 :
154 80 : delegate->OnHeader(header);
155 :
156 80 : const uint8_t * data = packetData.Start() + HeaderRef::kSizeBytes;
157 :
158 : {
159 80 : QueryData queryData;
160 136 : for (uint16_t i = 0; i < header.GetQueryCount(); i++)
161 : {
162 56 : if (!queryData.Parse(packetData, &data))
163 : {
164 0 : return false;
165 : }
166 :
167 56 : delegate->OnQuery(queryData);
168 : }
169 : }
170 :
171 : {
172 80 : ResourceData resourceData;
173 369 : for (uint16_t i = 0; i < header.GetAnswerCount(); i++)
174 : {
175 289 : if (!resourceData.Parse(packetData, &data))
176 : {
177 0 : return false;
178 : }
179 :
180 289 : delegate->OnResource(ResourceType::kAnswer, resourceData);
181 : }
182 :
183 80 : for (uint16_t i = 0; i < header.GetAuthorityCount(); i++)
184 : {
185 0 : if (!resourceData.Parse(packetData, &data))
186 : {
187 0 : return false;
188 : }
189 :
190 0 : delegate->OnResource(ResourceType::kAuthority, resourceData);
191 : }
192 :
193 102 : for (uint16_t i = 0; i < header.GetAdditionalCount(); i++)
194 : {
195 22 : if (!resourceData.Parse(packetData, &data))
196 : {
197 0 : return false;
198 : }
199 :
200 22 : delegate->OnResource(ResourceType::kAdditional, resourceData);
201 : }
202 : }
203 :
204 80 : return true;
205 : }
206 :
207 : } // namespace Minimal
208 : } // namespace mdns
|