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/logging.h" 8 #include "net/base/big_endian.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, uint32 ttl, 41 const std::string& service_name) { 42 std::string rdata; 43 bool success = net::DNSDomainFromDot(service_name, &rdata); 44 DCHECK(success); 45 46 AddResponse(service_type, net::dns_protocol::kTypePTR, ttl, rdata); 47 } 48 49 void DnsResponseBuilder::AppendSrv(const std::string& service_name, uint32 ttl, 50 uint16 priority, uint16 weight, 51 uint16 http_port, 52 const std::string& service_domain_name) { 53 std::string domain_name; 54 bool success = net::DNSDomainFromDot(service_domain_name, &domain_name); 55 DCHECK(success); 56 57 std::vector<uint8> rdata(2 + 2 + 2 + domain_name.size()); 58 59 net::BigEndianWriter writer(rdata.data(), rdata.size()); 60 success = writer.WriteU16(priority) && 61 writer.WriteU16(weight) && 62 writer.WriteU16(http_port) && 63 writer.WriteBytes(domain_name.data(), domain_name.size()); 64 DCHECK(success); 65 DCHECK_EQ(writer.remaining(), 0); // For warranty of correct size allocation. 66 67 AddResponse(service_name, net::dns_protocol::kTypeSRV, ttl, 68 std::string(rdata.begin(), rdata.end())); 69 } 70 71 void DnsResponseBuilder::AppendA(const std::string& service_domain_name, 72 uint32 ttl, net::IPAddressNumber http_ipv4) { 73 // TODO(maksymb): IP to send must depends on interface from where query was 74 // received. 75 if (http_ipv4.empty()) { 76 LOG(ERROR) << "Invalid IP"; 77 return; 78 } 79 80 AddResponse(service_domain_name, net::dns_protocol::kTypeA, ttl, 81 std::string(http_ipv4.begin(), http_ipv4.end())); 82 } 83 84 void DnsResponseBuilder::AppendTxt(const std::string& service_name, uint32 ttl, 85 const std::vector<std::string>& metadata) { 86 std::string rdata; 87 for (std::vector<std::string>::const_iterator str = metadata.begin(); 88 str != metadata.end(); ++str) { 89 int len = static_cast<int>(str->size()); 90 DCHECK_LT(len, 256); 91 rdata += static_cast<char>(len); // Set length byte. 92 rdata += *str; 93 } 94 95 AddResponse(service_name, net::dns_protocol::kTypeTXT, ttl, rdata); 96 } 97 98 scoped_refptr<net::IOBufferWithSize> DnsResponseBuilder::Build() { 99 size_t size = sizeof(header_); 100 for (std::vector<DnsResponseRecord>::const_iterator iter = responses_.begin(); 101 iter != responses_.end(); ++iter) { 102 size += iter->name.size() + 2 + // Two dots: first and last. 103 sizeof(iter->type) + sizeof(iter->klass) + sizeof(iter->ttl) + 104 2 + // sizeof(RDLENGTH) 105 iter->rdata.size(); 106 } 107 108 if (responses_.empty()) 109 return NULL; // No answer. 110 111 header_.ancount = static_cast<uint16>(responses_.size()); 112 113 scoped_refptr<net::IOBufferWithSize> message( 114 new net::IOBufferWithSize(static_cast<int>(size))); 115 net::BigEndianWriter writer(message->data(), message->size()); 116 bool success = writer.WriteU16(header_.id) && 117 writer.WriteU16(header_.flags) && 118 writer.WriteU16(header_.qdcount) && 119 writer.WriteU16(header_.ancount) && 120 writer.WriteU16(header_.nscount) && 121 writer.WriteU16(header_.arcount); 122 DCHECK(success); 123 124 std::string name_in_dns_format; 125 for (std::vector<DnsResponseRecord>::const_iterator iter = responses_.begin(); 126 iter != responses_.end(); ++iter) { 127 success = net::DNSDomainFromDot(iter->name, &name_in_dns_format); 128 DCHECK(success); 129 DCHECK_EQ(name_in_dns_format.size(), iter->name.size() + 2); 130 131 success = writer.WriteBytes(name_in_dns_format.data(), 132 name_in_dns_format.size()) && 133 writer.WriteU16(iter->type) && 134 writer.WriteU16(iter->klass) && 135 writer.WriteU32(iter->ttl) && 136 writer.WriteU16(static_cast<uint16>(iter->rdata.size())) && 137 writer.WriteBytes(iter->rdata.data(), iter->rdata.size()); 138 DCHECK(success); 139 } 140 141 DCHECK_EQ(writer.remaining(), 0); // For warranty of correct size allocation. 142 143 return message; 144 } 145 146 void DnsResponseBuilder::AddResponse(const std::string& name, uint16 type, 147 uint32 ttl, const std::string& rdata) { 148 DnsResponseRecord response; 149 response.name = name; 150 response.klass = klass; 151 response.ttl = ttl; 152 response.type = type; 153 response.rdata = rdata; 154 responses_.push_back(response); 155 } 156 157