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 688 : 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 688 : if (!validData.Contains(*start)) 99 : { 100 0 : return false; 101 : } 102 : 103 688 : const uint8_t * nameEnd = nullptr; 104 : 105 : { 106 688 : SerializedQNameIterator it(validData, *start); 107 688 : nameEnd = it.FindDataEnd(); 108 : } 109 688 : if (nameEnd == nullptr) 110 : { 111 0 : return false; 112 : } 113 : 114 : // need 3*u16 + u32 115 688 : if (!validData.Contains(nameEnd + 9)) 116 : { 117 0 : return false; 118 : } 119 : 120 688 : mType = static_cast<QType>(chip::Encoding::BigEndian::Read16(nameEnd)); 121 688 : mClass = static_cast<QClass>(chip::Encoding::BigEndian::Read16(nameEnd)); 122 688 : mTtl = chip::Encoding::BigEndian::Read32(nameEnd); 123 : 124 688 : uint16_t dataLen = chip::Encoding::BigEndian::Read16(nameEnd); // resource data 125 : 126 688 : if (!validData.Contains(nameEnd + dataLen - 1)) 127 : { 128 0 : return false; // no space for RDATA 129 : } 130 688 : mData = BytesRange(nameEnd, nameEnd + dataLen); 131 : 132 688 : mNameIterator = SerializedQNameIterator(validData, *start); 133 : 134 688 : *start = nameEnd + dataLen; 135 : 136 688 : return true; 137 : } 138 : 139 120 : bool ParsePacket(const BytesRange & packetData, ParserDelegate * delegate) 140 : { 141 120 : 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 120 : ConstHeaderRef header(packetData.Start()); 148 : 149 120 : if (!header.GetFlags().IsValidMdns()) 150 : { 151 0 : return false; 152 : } 153 : 154 120 : delegate->OnHeader(header); 155 : 156 120 : const uint8_t * data = packetData.Start() + HeaderRef::kSizeBytes; 157 : 158 : { 159 120 : QueryData queryData; 160 176 : 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 120 : ResourceData resourceData; 173 769 : for (uint16_t i = 0; i < header.GetAnswerCount(); i++) 174 : { 175 649 : if (!resourceData.Parse(packetData, &data)) 176 : { 177 0 : return false; 178 : } 179 : 180 649 : delegate->OnResource(ResourceType::kAnswer, resourceData); 181 : } 182 : 183 120 : 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 142 : 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 120 : return true; 205 : } 206 : 207 : } // namespace Minimal 208 : } // namespace mdns