| /* |
| * |
| * 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 <stdio.h> |
| |
| 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<QType>(chip::Encoding::BigEndian::Read16(nameEnd)); |
| |
| uint16_t klass = chip::Encoding::BigEndian::Read16(nameEnd); |
| |
| mAnswerViaUnicast = (klass & kQClassUnicastAnswerFlag) != 0; |
| mClass = static_cast<QClass>(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<uint16_t>(mType)) |
| .Put16(static_cast<uint16_t>(static_cast<uint16_t>(mClass) | (mAnswerViaUnicast ? kQClassUnicastAnswerFlag : 0))); |
| |
| if (!out.Fit()) |
| { |
| return false; |
| } |
| |
| hdr.SetQueryCount(static_cast<uint16_t>(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) |
| // <DATA> (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<QType>(chip::Encoding::BigEndian::Read16(nameEnd)); |
| mClass = static_cast<QClass>(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<ptrdiff_t>(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 |