blob: 3621ebbd94d3aa541e0d95df637f29f73cd0c4f1 [file]
// 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/encoding/dns_message.h"
namespace mdns {
DnsName::DnsName(std::string dotted_string) : dotted_string_(std::move(dotted_string)) {
if (dotted_string_.empty()) {
return;
}
if (!dotted_string_.ends_with(".")) {
dotted_string_ += ".";
}
first_label_size_ = dotted_string_.find('.');
}
DnsName::DnsName(std::string dotted_string, size_t first_label_size)
: dotted_string_(std::move(dotted_string)), first_label_size_(first_label_size) {
if (!dotted_string_.ends_with(".")) {
dotted_string_ += ".";
}
FX_DCHECK(first_label_size < dotted_string_.size());
}
DnsName DnsName::append(const DnsLabel& label) const {
DnsName result(*this);
result.push_back(label);
return result;
}
DnsName DnsName::append(const DnsName& name) const {
DnsName result(*this);
for (auto label = name.first_label_view(); !label.empty(); label = name.next_label_view(label)) {
result.push_back(DnsLabel(label));
}
return result;
}
void DnsName::push_back(const DnsLabel& label) {
if (dotted_string_.empty()) {
dotted_string_ = label + ".";
first_label_size_ = label.size();
return;
}
dotted_string_ += label + ".";
}
std::string_view DnsName::next_label_view(std::string_view current_label_view) const {
if (current_label_view.empty()) {
return std::string_view();
}
size_t pos = current_label_view.data() - dotted_string_.data();
FX_DCHECK(pos < dotted_string_.size());
pos += current_label_view.size();
if (pos >= dotted_string_.size()) {
return std::string_view();
}
pos += 1;
if (pos == dotted_string_.size()) {
return std::string_view();
}
auto data = dotted_string_.data() + pos;
auto end_pos = dotted_string_.find('.', pos);
FX_DCHECK(end_pos != std::string::npos);
return std::string_view(data, end_pos - pos);
}
void DnsHeader::SetResponse(bool value) {
if (value) {
flags_ |= kQueryResponseMask;
} else {
flags_ &= ~kQueryResponseMask;
}
}
void DnsHeader::SetOpCode(DnsOpCode op_code) {
flags_ &= ~kOpCodeMask;
flags_ |= static_cast<uint16_t>(op_code) << kOpCodeShift;
}
void DnsHeader::SetAuthoritativeAnswer(bool value) {
if (value) {
flags_ |= kAuthoritativeAnswerMask;
} else {
flags_ &= ~kAuthoritativeAnswerMask;
}
}
void DnsHeader::SetTruncated(bool value) {
if (value) {
flags_ |= kTruncationMask;
} else {
flags_ &= ~kTruncationMask;
}
}
void DnsHeader::SetRecursionDesired(bool value) {
if (value) {
flags_ |= kRecursionDesiredMask;
} else {
flags_ &= ~kRecursionDesiredMask;
}
}
void DnsHeader::SetRecursionAvailable(bool value) {
if (value) {
flags_ |= kRecursionAvailableMask;
} else {
flags_ &= ~kRecursionAvailableMask;
}
}
void DnsHeader::SetResponseCode(DnsResponseCode response_code) {
flags_ &= ~kResponseCodeMask;
flags_ |= static_cast<uint16_t>(response_code);
}
DnsQuestion::DnsQuestion() = default;
DnsQuestion::DnsQuestion(DnsName name, DnsType type) : name_(std::move(name)), type_(type) {}
DnsQuestion::DnsQuestion(DnsName name, DnsType type, bool request_unicast_response)
: name_(std::move(name)), type_(type), unicast_response_(request_unicast_response) {}
DnsResource::DnsResource() {}
DnsResource::DnsResource(DnsName name, DnsType type) : name_(std::move(name)), type_(type) {
switch (type_) {
case DnsType::kA:
new (&a_) DnsResourceDataA();
time_to_live_ = kShortTimeToLive;
// cache_flush_ false, because multiple A resources can apply to the same name.
break;
case DnsType::kNs:
new (&ns_) DnsResourceDataNs();
time_to_live_ = kLongTimeToLive;
cache_flush_ = true;
break;
case DnsType::kCName:
new (&cname_) DnsResourceDataCName();
time_to_live_ = kLongTimeToLive;
cache_flush_ = true;
break;
case DnsType::kPtr:
new (&ptr_) DnsResourceDataPtr();
time_to_live_ = kLongTimeToLive;
// cache_flush_ false, because multiple PTR resources can apply to the same name.
break;
case DnsType::kTxt:
new (&txt_) DnsResourceDataTxt();
time_to_live_ = kLongTimeToLive;
cache_flush_ = true;
break;
case DnsType::kAaaa:
new (&aaaa_) DnsResourceDataAaaa();
time_to_live_ = kShortTimeToLive;
// cache_flush_ false, because multiple AAAA resources can apply to the same name.
break;
case DnsType::kSrv:
new (&srv_) DnsResourceDataSrv();
time_to_live_ = kShortTimeToLive;
cache_flush_ = true;
break;
case DnsType::kOpt:
new (&opt_) DnsResourceDataOpt();
time_to_live_ = kShortTimeToLive;
cache_flush_ = true;
break;
case DnsType::kNSec:
new (&nsec_) DnsResourceDataNSec();
time_to_live_ = kLongTimeToLive;
cache_flush_ = true;
break;
default:
break;
}
}
DnsResource::DnsResource(DnsName name, inet::IpAddress address, bool cache_flush)
: name_(std::move(name)), cache_flush_(cache_flush) {
if (address.is_v4()) {
type_ = DnsType::kA;
new (&a_) DnsResourceDataA();
time_to_live_ = kShortTimeToLive;
a_.address_.address_ = address;
} else {
type_ = DnsType::kAaaa;
new (&aaaa_) DnsResourceDataAaaa();
time_to_live_ = kShortTimeToLive;
aaaa_.address_.address_ = address;
}
}
DnsResource::DnsResource(const DnsResource& other) {
name_ = other.name_;
type_ = other.type_;
class_ = other.class_;
cache_flush_ = other.cache_flush_;
time_to_live_ = other.time_to_live_;
switch (type_) {
case DnsType::kA:
new (&a_) DnsResourceDataA();
a_ = other.a_;
break;
case DnsType::kNs:
new (&ns_) DnsResourceDataNs();
ns_ = other.ns_;
break;
case DnsType::kCName:
new (&cname_) DnsResourceDataCName();
cname_ = other.cname_;
break;
case DnsType::kPtr:
new (&ptr_) DnsResourceDataPtr();
ptr_ = other.ptr_;
break;
case DnsType::kTxt:
new (&txt_) DnsResourceDataTxt();
txt_ = other.txt_;
break;
case DnsType::kAaaa:
new (&aaaa_) DnsResourceDataAaaa();
aaaa_ = other.aaaa_;
break;
case DnsType::kSrv:
new (&srv_) DnsResourceDataSrv();
srv_ = other.srv_;
break;
case DnsType::kOpt:
new (&opt_) DnsResourceDataOpt();
opt_ = other.opt_;
break;
case DnsType::kNSec:
new (&nsec_) DnsResourceDataNSec();
nsec_ = other.nsec_;
break;
default:
break;
}
}
DnsResource::~DnsResource() {
switch (type_) {
case DnsType::kA:
a_.~DnsResourceDataA();
break;
case DnsType::kNs:
ns_.~DnsResourceDataNs();
break;
case DnsType::kCName:
cname_.~DnsResourceDataCName();
break;
case DnsType::kPtr:
ptr_.~DnsResourceDataPtr();
break;
case DnsType::kTxt:
txt_.~DnsResourceDataTxt();
break;
case DnsType::kAaaa:
aaaa_.~DnsResourceDataAaaa();
break;
case DnsType::kSrv:
srv_.~DnsResourceDataSrv();
break;
case DnsType::kOpt:
opt_.~DnsResourceDataOpt();
break;
case DnsType::kNSec:
nsec_.~DnsResourceDataNSec();
break;
default:
break;
}
}
} // namespace mdns