blob: 254690782942b01d094ba3afd932b051ea157c2e [file] [log] [blame]
// 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 "src/connectivity/network/mdns/service/dns_writing.h"
#include <lib/syslog/cpp/macros.h>
#include <limits>
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) {
FX_DCHECK(value.address_.is_v4());
writer.PutBytes(value.address_.byte_count(), value.address_.as_bytes());
return writer;
}
PacketWriter& operator<<(PacketWriter& writer, const DnsV6Address& value) {
FX_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:
FX_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) {
FX_DCHECK(value.header_.question_count_ == value.questions_.size());
FX_DCHECK(value.header_.answer_count_ == value.answers_.size());
FX_DCHECK(value.header_.authority_count_ == value.authorities_.size());
FX_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