void DNS::add_record(const resource& resource, const sections_type& sections) { // We need to check that the data provided is correct. Otherwise, the sections // will end up being inconsistent. IPv4Address v4_addr; IPv6Address v6_addr; string buffer = encode_domain_name(resource.dname()), encoded_data; // By default the data size is the length of the data field. size_t data_size = resource.data().size(); if (resource.query_type() == A) { v4_addr = resource.data(); data_size = 4; } else if (resource.query_type() == AAAA) { v6_addr = resource.data(); data_size = IPv6Address::address_size; } else if (contains_dname(resource.query_type())) { encoded_data = encode_domain_name(resource.data()); data_size = encoded_data.size(); } size_t offset = buffer.size() + sizeof(uint16_t) * 3 + sizeof(uint32_t) + data_size, threshold = sections.empty() ? records_data_.size() :* sections.front().first; // Take into account the MX preference field if (resource.query_type() == MX) { offset += sizeof(uint16_t); } for (size_t i = 0; i < sections.size(); ++i) { update_records( *sections[i].first, sections[i].second, static_cast<uint32_t>(threshold), static_cast<uint32_t>(offset) ); } records_data_.insert( records_data_.begin() + threshold, offset, 0 ); OutputMemoryStream stream(&records_data_[0] + threshold, offset); stream.write(buffer.begin(), buffer.end()); stream.write_be(resource.query_type()); stream.write_be(resource.query_class()); stream.write_be(resource.ttl()); stream.write_be<uint16_t>(data_size + (resource.query_type() == MX ? 2 : 0)); if (resource.query_type() == MX) { stream.write_be(resource.preference()); } if (resource.query_type() == A) { stream.write(v4_addr); } else if (resource.query_type() == AAAA) { stream.write(v6_addr); } else if (!encoded_data.empty()) { stream.write(encoded_data.begin(), encoded_data.end()); } else { stream.write(resource.data().begin(), resource.data().end()); } }
void DNS::add_record(const Resource &resource, const sections_type §ions) { // We need to check that the data provided is correct. Otherwise, the sections // will end up being inconsistent. IPv4Address v4_addr; IPv6Address v6_addr; std::string buffer = encode_domain_name(resource.dname()), encoded_data; // By default the data size is the length of the data field. uint32_t data_size = resource.data().size(); if(resource.type() == A) { v4_addr = resource.data(); data_size = 4; } else if(resource.type() == AAAA) { v6_addr = resource.data(); data_size = IPv6Address::address_size; } else if(contains_dname(resource.type())) { encoded_data = encode_domain_name(resource.data()); data_size = encoded_data.size(); } uint32_t offset = buffer.size() + sizeof(uint16_t) * 3 + sizeof(uint32_t) + data_size, threshold = sections.empty() ? records_data.size() : *sections.front().first; // Skip the preference field if(resource.type() == MX) { offset += sizeof(uint16_t); } for(size_t i = 0; i < sections.size(); ++i) { update_records(*sections[i].first, sections[i].second, threshold, offset); } records_data.insert( records_data.begin() + threshold, offset, 0 ); uint8_t *ptr = std::copy( buffer.begin(), buffer.end(), &records_data[threshold] ); uint16_t uint16_t_buffer; uint32_t uint32_t_buffer; uint16_t_buffer = Endian::host_to_be(resource.type()); std::memcpy(ptr, &uint16_t_buffer, sizeof(uint16_t)); ptr += sizeof(uint16_t); uint16_t_buffer = Endian::host_to_be(resource.query_class()); std::memcpy(ptr, &uint16_t_buffer, sizeof(uint16_t)); ptr += sizeof(uint16_t); uint32_t_buffer = Endian::host_to_be(resource.ttl()); std::memcpy(ptr, &uint32_t_buffer, sizeof(uint32_t)); ptr += sizeof(uint32_t); uint16_t_buffer = Endian::host_to_be<uint16_t>( data_size + (resource.type() == MX ? 2 : 0) ); std::memcpy(ptr, &uint16_t_buffer, sizeof(uint16_t)); ptr += sizeof(uint16_t); if(resource.type() == MX) { ptr += sizeof(uint16_t); } if(resource.type() == A) { uint32_t ip_int = v4_addr; std::memcpy(ptr, &ip_int, sizeof(ip_int)); } else if(resource.type() == AAAA) { std::copy(v6_addr.begin(), v6_addr.end(), ptr); } else if(!encoded_data.empty()) { std::copy(encoded_data.begin(), encoded_data.end(), ptr); } else { std::copy(resource.data().begin(), resource.data().end(), ptr); } }