| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "garnet/bin/mdns/service/dns_writing.h" |
| |
| #include <limits> |
| |
| #include "src/lib/fxl/logging.h" |
| |
| namespace mdns { |
| |
| PacketWriter& operator<<(PacketWriter& writer, const DnsName& value) { |
| std::string s = value.dotted_string_; |
| |
| while (!s.empty()) { |
| size_t position = writer.GetBookmarkPosition(s); |
| if (position != PacketWriter::npos) { |
| // Write a name offset. |
| uint16_t offset = static_cast<uint16_t>(position) | 0xc000; |
| writer << offset; |
| return writer; |
| } |
| |
| writer.CreateBookmark(s); |
| |
| size_t dot_pos = s.find('.'); |
| |
| if (dot_pos == std::string::npos) { |
| // There really should be a dot at the end, but there is not. |
| writer << static_cast<uint8_t>(s.size()); |
| writer.PutBytes(s.size(), s.data()); |
| break; |
| } |
| |
| writer << static_cast<uint8_t>(dot_pos); |
| writer.PutBytes(dot_pos, s.data()); |
| s = s.substr(dot_pos + 1); |
| } |
| |
| return writer << static_cast<uint8_t>(0); |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, const DnsV4Address& value) { |
| FXL_DCHECK(value.address_.is_v4()); |
| writer.PutBytes(value.address_.byte_count(), value.address_.as_bytes()); |
| return writer; |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, const DnsV6Address& value) { |
| FXL_DCHECK(value.address_.is_v6()); |
| writer.PutBytes(value.address_.byte_count(), value.address_.as_bytes()); |
| return writer; |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, const DnsType& value) { |
| uint16_t as_uint16 = static_cast<uint16_t>(value); |
| return writer << as_uint16; |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, const DnsClass& value) { |
| uint16_t as_uint16 = static_cast<uint16_t>(value); |
| return writer << as_uint16; |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, const DnsClassAndFlag& value) { |
| uint16_t as_uint16 = static_cast<uint16_t>(value.class_); |
| if (value.flag_) { |
| as_uint16 |= 0x8000; |
| } |
| return writer << as_uint16; |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, const DnsHeader& value) { |
| return writer << value.id_ << value.flags_ << value.question_count_ |
| << value.answer_count_ << value.authority_count_ |
| << value.additional_count_; |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, const DnsQuestion& value) { |
| DnsClassAndFlag class_and_flag; |
| class_and_flag.class_ = value.class_; |
| class_and_flag.flag_ = value.unicast_response_; |
| return writer << value.name_ << value.type_ << class_and_flag; |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, const DnsResourceDataA& value) { |
| return writer << value.address_; |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, const DnsResourceDataNs& value) { |
| return writer << value.name_server_domain_name_; |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, |
| const DnsResourceDataCName& value) { |
| return writer << value.canonical_name_; |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, |
| const DnsResourceDataPtr& value) { |
| return writer << value.pointer_domain_name_; |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, |
| const DnsResourceDataTxt& value) { |
| for (auto& string : value.strings_) { |
| if (string.size() > std::numeric_limits<uint8_t>::max()) { |
| continue; |
| } |
| |
| writer << static_cast<uint8_t>(string.size()); |
| writer.PutBytes(string.size(), string.data()); |
| } |
| |
| return writer << static_cast<uint8_t>(0); |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, |
| const DnsResourceDataAaaa& value) { |
| return writer << value.address_; |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, |
| const DnsResourceDataSrv& value) { |
| return writer << value.priority_ << value.weight_ << value.port_.as_uint16_t() |
| << value.target_; |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, |
| const DnsResourceDataOpt& value) { |
| uint16_t length = value.options_.size(); |
| return writer << length << value.options_; |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, |
| const DnsResourceDataNSec& value) { |
| return writer << value.next_domain_ << value.bits_; |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, const DnsResource& value) { |
| DnsClassAndFlag class_and_flag; |
| class_and_flag.class_ = value.class_; |
| class_and_flag.flag_ = value.cache_flush_; |
| |
| writer << value.name_ << value.type_ << class_and_flag << value.time_to_live_; |
| |
| // Note where the data size goes and write a placeholder. |
| size_t data_size_position = writer.position(); |
| uint16_t data_size = 0; |
| |
| writer << data_size; |
| |
| switch (value.type_) { |
| case DnsType::kA: |
| writer << value.a_; |
| break; |
| case DnsType::kNs: |
| writer << value.ns_; |
| break; |
| case DnsType::kCName: |
| writer << value.cname_; |
| break; |
| case DnsType::kPtr: |
| writer << value.ptr_; |
| break; |
| case DnsType::kTxt: |
| writer << value.txt_; |
| break; |
| case DnsType::kAaaa: |
| writer << value.aaaa_; |
| break; |
| case DnsType::kSrv: |
| writer << value.srv_; |
| break; |
| case DnsType::kOpt: |
| writer << value.opt_; |
| break; |
| case DnsType::kNSec: |
| writer << value.nsec_; |
| break; |
| default: |
| FXL_DCHECK(false) << "Unsupported resource type " |
| << static_cast<uint16_t>(value.type_); |
| break; |
| } |
| |
| // Determine the size of the data and prefix the data with it. |
| size_t end_position = writer.position(); |
| data_size = end_position - data_size_position - sizeof(data_size); |
| writer.SetPosition(data_size_position); |
| writer << data_size; |
| writer.SetPosition(end_position); |
| |
| return writer; |
| } |
| |
| PacketWriter& operator<<(PacketWriter& writer, const DnsMessage& value) { |
| FXL_DCHECK(value.header_.question_count_ == value.questions_.size()); |
| FXL_DCHECK(value.header_.answer_count_ == value.answers_.size()); |
| FXL_DCHECK(value.header_.authority_count_ == value.authorities_.size()); |
| FXL_DCHECK(value.header_.additional_count_ == value.additionals_.size()); |
| |
| writer << value.header_; |
| |
| for (uint16_t i = 0; i < value.questions_.size(); ++i) { |
| writer << value.questions_[i]; |
| } |
| |
| for (uint16_t i = 0; i < value.answers_.size(); ++i) { |
| writer << value.answers_[i]; |
| } |
| |
| for (uint16_t i = 0; i < value.authorities_.size(); ++i) { |
| writer << value.authorities_[i]; |
| } |
| |
| for (uint16_t i = 0; i < value.additionals_.size(); ++i) { |
| writer << value.additionals_[i]; |
| } |
| |
| return writer; |
| } |
| |
| } // namespace mdns |