1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "cloud_print/gcp20/prototype/dns_response_builder.h" 6 7 #include "base/big_endian.h" 8 #include "base/logging.h" 9 #include "net/base/dns_util.h" 10 #include "net/base/io_buffer.h" 11 #include "net/base/ip_endpoint.h" 12 #include "net/dns/dns_response.h" 13 14 namespace { 15 16 uint16 klass = net::dns_protocol::kClassIN; 17 18 } // namespace 19 20 DnsResponseRecord::DnsResponseRecord() : type(0), klass(0), ttl(0) { 21 } 22 23 DnsResponseRecord::~DnsResponseRecord() { 24 } 25 26 DnsResponseBuilder::DnsResponseBuilder(uint16 id) { 27 header_.id = id; 28 // TODO(maksymb): Check do we need AA flag enabled. 29 header_.flags = net::dns_protocol::kFlagResponse | 30 net::dns_protocol::kFlagAA; 31 header_.qdcount = 0; 32 header_.ancount = 0; 33 header_.nscount = 0; 34 header_.arcount = 0; 35 } 36 37 DnsResponseBuilder::~DnsResponseBuilder() { 38 } 39 40 void DnsResponseBuilder::AppendPtr(const std::string& service_type, 41 uint32 ttl, 42 const std::string& service_name, 43 bool answer) { 44 std::string rdata; 45 bool success = net::DNSDomainFromDot(service_name, &rdata); 46 DCHECK(success); 47 48 AddResponse(service_type, net::dns_protocol::kTypePTR, ttl, rdata, answer); 49 } 50 51 void DnsResponseBuilder::AppendSrv(const std::string& service_name, 52 uint32 ttl, 53 uint16 priority, 54 uint16 weight, 55 uint16 http_port, 56 const std::string& service_domain_name, 57 bool answer) { 58 std::string domain_name; 59 bool success = net::DNSDomainFromDot(service_domain_name, &domain_name); 60 DCHECK(success); 61 62 std::vector<uint8> rdata(2 + 2 + 2 + domain_name.size()); 63 64 base::BigEndianWriter writer(reinterpret_cast<char*>(rdata.data()), 65 rdata.size()); 66 success = writer.WriteU16(priority) && 67 writer.WriteU16(weight) && 68 writer.WriteU16(http_port) && 69 writer.WriteBytes(domain_name.data(), domain_name.size()); 70 DCHECK(success); 71 DCHECK_EQ(writer.remaining(), 0); // For warranty of correct size allocation. 72 73 AddResponse(service_name, net::dns_protocol::kTypeSRV, ttl, 74 std::string(rdata.begin(), rdata.end()), answer); 75 } 76 77 void DnsResponseBuilder::AppendA(const std::string& service_domain_name, 78 uint32 ttl, 79 net::IPAddressNumber http_ipv4, 80 bool answer) { 81 // TODO(maksymb): IP to send must depends on interface from where query was 82 // received. 83 if (http_ipv4.empty()) { 84 return; 85 } 86 87 AddResponse(service_domain_name, net::dns_protocol::kTypeA, ttl, 88 std::string(http_ipv4.begin(), http_ipv4.end()), answer); 89 } 90 91 void DnsResponseBuilder::AppendAAAA(const std::string& service_domain_name, 92 uint32 ttl, 93 net::IPAddressNumber http_ipv6, 94 bool answer) { 95 // TODO(maksymb): IP to send must depends on interface from where query was 96 // received. 97 if (http_ipv6.empty()) { 98 return; 99 } 100 101 AddResponse(service_domain_name, net::dns_protocol::kTypeAAAA, ttl, 102 std::string(http_ipv6.begin(), http_ipv6.end()), answer); 103 } 104 105 void DnsResponseBuilder::AppendTxt(const std::string& service_name, 106 uint32 ttl, 107 const std::vector<std::string>& metadata, 108 bool answer) { 109 std::string rdata; 110 for (std::vector<std::string>::const_iterator str = metadata.begin(); 111 str != metadata.end(); ++str) { 112 int len = static_cast<int>(str->size()); 113 DCHECK_LT(len, 256); 114 rdata += static_cast<char>(len); // Set length byte. 115 rdata += *str; 116 } 117 118 AddResponse(service_name, net::dns_protocol::kTypeTXT, ttl, rdata, answer); 119 } 120 121 scoped_refptr<net::IOBufferWithSize> DnsResponseBuilder::Build() { 122 size_t size = sizeof(header_); 123 for (std::vector<DnsResponseRecord>::const_iterator iter = responses_.begin(); 124 iter != responses_.end(); ++iter) { 125 size += iter->name.size() + 2 + // Two dots: first and last. 126 sizeof(iter->type) + sizeof(iter->klass) + sizeof(iter->ttl) + 127 2 + // sizeof(RDLENGTH) 128 iter->rdata.size(); 129 } 130 131 if (responses_.empty()) 132 return NULL; // No answer. 133 134 DCHECK_EQ(static_cast<size_t>(header_.ancount + header_.arcount), 135 responses_.size()); 136 scoped_refptr<net::IOBufferWithSize> message( 137 new net::IOBufferWithSize(static_cast<int>(size))); 138 base::BigEndianWriter writer(message->data(), message->size()); 139 bool success = writer.WriteU16(header_.id) && 140 writer.WriteU16(header_.flags) && 141 writer.WriteU16(header_.qdcount) && 142 writer.WriteU16(header_.ancount) && 143 writer.WriteU16(header_.nscount) && 144 writer.WriteU16(header_.arcount); 145 DCHECK(success); 146 147 std::string name_in_dns_format; 148 for (std::vector<DnsResponseRecord>::const_iterator iter = responses_.begin(); 149 iter != responses_.end(); ++iter) { 150 success = net::DNSDomainFromDot(iter->name, &name_in_dns_format); 151 DCHECK(success); 152 DCHECK_EQ(name_in_dns_format.size(), iter->name.size() + 2); 153 154 success = writer.WriteBytes(name_in_dns_format.data(), 155 name_in_dns_format.size()) && 156 writer.WriteU16(iter->type) && 157 writer.WriteU16(iter->klass) && 158 writer.WriteU32(iter->ttl) && 159 writer.WriteU16(static_cast<uint16>(iter->rdata.size())) && 160 writer.WriteBytes(iter->rdata.data(), iter->rdata.size()); 161 DCHECK(success); 162 } 163 164 DCHECK_EQ(writer.remaining(), 0); // For warranty of correct size allocation. 165 166 return message; 167 } 168 169 void DnsResponseBuilder::AddResponse(const std::string& name, 170 uint16 type, 171 uint32 ttl, 172 const std::string& rdata, 173 bool answer) { 174 DnsResponseRecord response; 175 response.name = name; 176 response.klass = klass; 177 response.ttl = ttl; 178 response.type = type; 179 response.rdata = rdata; 180 181 if (answer) { 182 responses_.insert(responses_.begin() + header_.ancount, response); 183 ++header_.ancount; 184 } else { 185 responses_.push_back(response); 186 ++header_.arcount; 187 } 188 } 189 190