/* * * Copyright (c) 2020 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "Parser.h" #include "Query.h" #include namespace mdns { namespace Minimal { bool QueryData::Parse(const BytesRange & validData, const uint8_t ** start) { // Structure is: // QNAME // TYPE // CLASS (plus a flag for unicast) if (!validData.Contains(*start)) { return false; } const uint8_t * nameEnd = nullptr; { SerializedQNameIterator it(validData, *start); nameEnd = it.FindDataEnd(); } if (nameEnd == nullptr) { return false; } if (!validData.Contains(nameEnd + 3)) { return false; } // TODO: should there be checks for valid mType/class? mType = static_cast(chip::Encoding::BigEndian::Read16(nameEnd)); uint16_t klass = chip::Encoding::BigEndian::Read16(nameEnd); mAnswerViaUnicast = (klass & kQClassUnicastAnswerFlag) != 0; mClass = static_cast(klass & ~kQClassUnicastAnswerFlag); mNameIterator = SerializedQNameIterator(validData, *start); *start = nameEnd; return true; } bool QueryData::Append(HeaderRef & hdr, RecordWriter & out) const { if ((hdr.GetAdditionalCount() != 0) || (hdr.GetAnswerCount() != 0) || (hdr.GetAuthorityCount() != 0)) { return false; } out.WriteQName(GetName()) .Put16(static_cast(mType)) .Put16(static_cast(static_cast(mClass) | (mAnswerViaUnicast ? kQClassUnicastAnswerFlag : 0))); if (!out.Fit()) { return false; } hdr.SetQueryCount(static_cast(hdr.GetQueryCount() + 1)); return true; } bool ResourceData::Parse(const BytesRange & validData, const uint8_t ** start) { // Structure is: // QNAME // TYPE (16 bit) // CLASS (16 bit) // TTL (32 bit) // RDLENGTH (16 bit) // (RDLENGTH bytes) if (!validData.Contains(*start)) { return false; } const uint8_t * nameEnd = nullptr; { SerializedQNameIterator it(validData, *start); nameEnd = it.FindDataEnd(); } if (nameEnd == nullptr) { return false; } // need 3*u16 + u32 if (!validData.Contains(nameEnd + 9)) { return false; } mType = static_cast(chip::Encoding::BigEndian::Read16(nameEnd)); mClass = static_cast(chip::Encoding::BigEndian::Read16(nameEnd)); mTtl = chip::Encoding::BigEndian::Read32(nameEnd); uint16_t dataLen = chip::Encoding::BigEndian::Read16(nameEnd); // resource data if (!validData.Contains(nameEnd + dataLen - 1)) { return false; // no space for RDATA } mData = BytesRange(nameEnd, nameEnd + dataLen); mNameIterator = SerializedQNameIterator(validData, *start); *start = nameEnd + dataLen; return true; } bool ParsePacket(const BytesRange & packetData, ParserDelegate * delegate) { if (packetData.Size() < static_cast(HeaderRef::kSizeBytes)) { return false; } // header is used as const, so cast is safe ConstHeaderRef header(packetData.Start()); if (!header.GetFlags().IsValidMdns()) { return false; } delegate->OnHeader(header); const uint8_t * data = packetData.Start() + HeaderRef::kSizeBytes; { QueryData queryData; for (uint16_t i = 0; i < header.GetQueryCount(); i++) { if (!queryData.Parse(packetData, &data)) { return false; } delegate->OnQuery(queryData); } } { ResourceData resourceData; for (uint16_t i = 0; i < header.GetAnswerCount(); i++) { if (!resourceData.Parse(packetData, &data)) { return false; } delegate->OnResource(ResourceType::kAnswer, resourceData); } for (uint16_t i = 0; i < header.GetAuthorityCount(); i++) { if (!resourceData.Parse(packetData, &data)) { return false; } delegate->OnResource(ResourceType::kAuthority, resourceData); } for (uint16_t i = 0; i < header.GetAdditionalCount(); i++) { if (!resourceData.Parse(packetData, &data)) { return false; } delegate->OnResource(ResourceType::kAdditional, resourceData); } } return true; } } // namespace Minimal } // namespace mdns