mirror of
https://github.com/mfontanini/libtins
synced 2026-01-26 20:01:35 +01:00
Code cleanup and use same syntax on the entire project
Initial code cleanup More code cleanup Cleanup more code Cleanup Dot11 code Fix OSX build issue Cleanup examples Fix ref and pointer declaration syntax Fix braces
This commit is contained in:
448
src/dns.cpp
448
src/dns.cpp
@@ -41,7 +41,10 @@
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::string;
|
||||
using std::copy;
|
||||
using std::memcpy;
|
||||
using std::list;
|
||||
using std::make_pair;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
@@ -49,259 +52,232 @@ using Tins::Memory::OutputMemoryStream;
|
||||
namespace Tins {
|
||||
|
||||
DNS::DNS()
|
||||
: dns(), answers_idx(), authority_idx(), additional_idx()
|
||||
{
|
||||
: header_(), answers_idx_(), authority_idx_(), additional_idx_() {
|
||||
}
|
||||
|
||||
DNS::DNS(const uint8_t *buffer, uint32_t total_sz)
|
||||
: answers_idx(), authority_idx(), additional_idx()
|
||||
{
|
||||
DNS::DNS(const uint8_t* buffer, uint32_t total_sz)
|
||||
: answers_idx_(), authority_idx_(), additional_idx_() {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(dns);
|
||||
records_data.assign(stream.pointer(), stream.pointer() + stream.size());
|
||||
stream.read(header_);
|
||||
stream.read(records_data_, stream.size());
|
||||
// Avoid doing this if there's no data. Otherwise VS's asserts fail.
|
||||
if (!records_data.empty()) {
|
||||
buffer = &records_data[0];
|
||||
const uint8_t *end = &records_data[0] + records_data.size(), *prev_start = buffer;
|
||||
if (!records_data_.empty()) {
|
||||
InputMemoryStream stream(records_data_);
|
||||
uint16_t nquestions = questions_count();
|
||||
for(uint16_t i(0); i < nquestions; ++i) {
|
||||
buffer = find_dname_end(buffer);
|
||||
if((buffer + (sizeof(uint16_t) * 2)) > end)
|
||||
throw malformed_packet();
|
||||
buffer += sizeof(uint16_t) * 2;
|
||||
for (uint16_t i(0); i < nquestions; ++i) {
|
||||
skip_to_dname_end(stream);
|
||||
stream.skip(sizeof(uint16_t) * 2);
|
||||
}
|
||||
answers_idx = static_cast<uint32_t>(buffer - prev_start);
|
||||
authority_idx = static_cast<uint32_t>(
|
||||
find_section_end(&records_data[0] + answers_idx, answers_count()) - &records_data[0]
|
||||
);
|
||||
additional_idx = static_cast<uint32_t>(
|
||||
find_section_end(&records_data[0] + authority_idx, authority_count()) - &records_data[0]
|
||||
);
|
||||
const uint8_t* base_offset = &records_data_[0];
|
||||
answers_idx_ = static_cast<uint32_t>(stream.pointer() - base_offset);
|
||||
skip_to_section_end(stream, answers_count());
|
||||
authority_idx_ = static_cast<uint32_t>(stream.pointer() - base_offset);
|
||||
skip_to_section_end(stream, authority_count());
|
||||
additional_idx_ = static_cast<uint32_t>(stream.pointer() - base_offset);
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t* DNS::find_dname_end(const uint8_t *ptr) const {
|
||||
const uint8_t *end = &records_data[0] + records_data.size();
|
||||
while(ptr < end) {
|
||||
if(*ptr == 0) {
|
||||
++ptr;
|
||||
void DNS::skip_to_dname_end(InputMemoryStream& stream) const {
|
||||
while (stream) {
|
||||
uint8_t value = stream.read<uint8_t>();
|
||||
if (value == 0) {
|
||||
// Found the ending null byte, we're done
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if((*ptr & 0xc0)) {
|
||||
ptr += sizeof(uint16_t);
|
||||
if ((value & 0xc0)) {
|
||||
// This is an offset label, skip the second byte and we're done
|
||||
stream.skip(1);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
uint8_t size = *ptr;
|
||||
ptr += size + 1;
|
||||
// This is an actual label, skip its contents
|
||||
stream.skip(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
const uint8_t *DNS::find_section_end(const uint8_t *ptr, const uint32_t num_records) const {
|
||||
const uint8_t *end = &records_data[0] + records_data.size();
|
||||
uint16_t uint16_t_buffer;
|
||||
for(uint32_t i = 0; i < num_records; ++i) {
|
||||
ptr = find_dname_end(ptr);
|
||||
if(ptr + sizeof(uint16_t) * 3 + sizeof(uint32_t) > end)
|
||||
void DNS::skip_to_section_end(InputMemoryStream& stream,
|
||||
const uint32_t num_records) const {
|
||||
for (uint32_t i = 0; i < num_records; ++i) {
|
||||
skip_to_dname_end(stream);
|
||||
stream.skip(sizeof(uint16_t) * 2 + sizeof(uint32_t));
|
||||
uint16_t data_size = stream.read_be<uint16_t>();
|
||||
if (!stream.can_read(data_size)) {
|
||||
throw malformed_packet();
|
||||
ptr += sizeof(uint16_t) * 2 + sizeof(uint32_t);
|
||||
std::memcpy(&uint16_t_buffer, ptr, sizeof(uint16_t));
|
||||
uint16_t data_size = Endian::be_to_host(uint16_t_buffer); // Data size
|
||||
ptr += sizeof(uint16_t);
|
||||
if(ptr + data_size > end)
|
||||
throw malformed_packet();
|
||||
ptr += data_size;
|
||||
}
|
||||
stream.skip(data_size);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint32_t DNS::header_size() const {
|
||||
return static_cast<uint32_t>(sizeof(dns) + records_data.size());
|
||||
return static_cast<uint32_t>(sizeof(header_) + records_data_.size());
|
||||
}
|
||||
|
||||
void DNS::id(uint16_t new_id) {
|
||||
dns.id = Endian::host_to_be(new_id);
|
||||
header_.id = Endian::host_to_be(new_id);
|
||||
}
|
||||
|
||||
void DNS::type(QRType new_qr) {
|
||||
dns.qr = new_qr;
|
||||
header_.qr = new_qr;
|
||||
}
|
||||
|
||||
void DNS::opcode(uint8_t new_opcode) {
|
||||
dns.opcode = new_opcode;
|
||||
header_.opcode = new_opcode;
|
||||
}
|
||||
|
||||
void DNS::authoritative_answer(uint8_t new_aa) {
|
||||
dns.aa = new_aa;
|
||||
header_.aa = new_aa;
|
||||
}
|
||||
|
||||
void DNS::truncated(uint8_t new_tc) {
|
||||
dns.tc = new_tc;
|
||||
header_.tc = new_tc;
|
||||
}
|
||||
|
||||
void DNS::recursion_desired(uint8_t new_rd) {
|
||||
dns.rd = new_rd;
|
||||
header_.rd = new_rd;
|
||||
}
|
||||
|
||||
void DNS::recursion_available(uint8_t new_ra) {
|
||||
dns.ra = new_ra;
|
||||
header_.ra = new_ra;
|
||||
}
|
||||
|
||||
void DNS::z(uint8_t new_z) {
|
||||
dns.z = new_z;
|
||||
header_.z = new_z;
|
||||
}
|
||||
|
||||
void DNS::authenticated_data(uint8_t new_ad) {
|
||||
dns.ad = new_ad;
|
||||
header_.ad = new_ad;
|
||||
}
|
||||
|
||||
void DNS::checking_disabled(uint8_t new_cd) {
|
||||
dns.cd = new_cd;
|
||||
header_.cd = new_cd;
|
||||
}
|
||||
|
||||
void DNS::rcode(uint8_t new_rcode) {
|
||||
dns.rcode = new_rcode;
|
||||
header_.rcode = new_rcode;
|
||||
}
|
||||
|
||||
bool DNS::contains_dname(uint16_t type) {
|
||||
return type == MX || type == CNAME ||
|
||||
type == PTR || type == NS;
|
||||
return type == MX || type == CNAME || type == PTR || type == NS;
|
||||
}
|
||||
|
||||
void DNS::add_query(const Query &query) {
|
||||
void DNS::add_query(const Query& query) {
|
||||
string new_str = encode_domain_name(query.dname());
|
||||
// Type (2 bytes) + Class (2 Bytes)
|
||||
size_t previous_length = new_str.size();
|
||||
// Epand the string to hold: Type (2 bytes) + Class (2 Bytes)
|
||||
new_str.insert(new_str.end(), sizeof(uint16_t) * 2, ' ');
|
||||
uint16_t uint16_t_buffer;
|
||||
uint16_t_buffer = Endian::host_to_be<uint16_t>(query.type());
|
||||
std::memcpy(&new_str[new_str.size() - 4], &uint16_t_buffer, sizeof(uint16_t));
|
||||
uint16_t_buffer = Endian::host_to_be<uint16_t>(query.query_class());
|
||||
std::memcpy(&new_str[new_str.size() - 2], &uint16_t_buffer, sizeof(uint16_t));
|
||||
// Build a stream at the end
|
||||
OutputMemoryStream stream(
|
||||
(uint8_t*)&new_str[0] + previous_length,
|
||||
sizeof(uint16_t) * 2
|
||||
);
|
||||
stream.write_be<uint16_t>(query.type());
|
||||
stream.write_be<uint16_t>(query.query_class());
|
||||
|
||||
uint32_t offset = static_cast<uint32_t>(new_str.size()), threshold = answers_idx;
|
||||
update_records(answers_idx, answers_count(), threshold, offset);
|
||||
update_records(authority_idx, authority_count(), threshold, offset);
|
||||
update_records(additional_idx, additional_count(), threshold, offset);
|
||||
records_data.insert(
|
||||
records_data.begin() + threshold,
|
||||
uint32_t offset = static_cast<uint32_t>(new_str.size()), threshold = answers_idx_;
|
||||
update_records(answers_idx_, answers_count(), threshold, offset);
|
||||
update_records(authority_idx_, authority_count(), threshold, offset);
|
||||
update_records(additional_idx_, additional_count(), threshold, offset);
|
||||
records_data_.insert(
|
||||
records_data_.begin() + threshold,
|
||||
new_str.begin(),
|
||||
new_str.end()
|
||||
);
|
||||
dns.questions = Endian::host_to_be(static_cast<uint16_t>(questions_count() + 1));
|
||||
header_.questions = Endian::host_to_be(static_cast<uint16_t>(questions_count() + 1));
|
||||
}
|
||||
|
||||
void DNS::add_answer(const Resource &resource) {
|
||||
void DNS::add_answer(const Resource& resource) {
|
||||
sections_type sections;
|
||||
sections.push_back(std::make_pair(&authority_idx, authority_count()));
|
||||
sections.push_back(std::make_pair(&additional_idx, additional_count()));
|
||||
sections.push_back(make_pair(&authority_idx_, authority_count()));
|
||||
sections.push_back(make_pair(&additional_idx_, additional_count()));
|
||||
add_record(resource, sections);
|
||||
dns.answers = Endian::host_to_be<uint16_t>(
|
||||
header_.answers = Endian::host_to_be<uint16_t>(
|
||||
answers_count() + 1
|
||||
);
|
||||
}
|
||||
|
||||
void DNS::add_record(const Resource &resource, const sections_type §ions) {
|
||||
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;
|
||||
std::string buffer = encode_domain_name(resource.dname()), encoded_data;
|
||||
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.type() == A) {
|
||||
if (resource.type() == A) {
|
||||
v4_addr = resource.data();
|
||||
data_size = 4;
|
||||
}
|
||||
else if(resource.type() == AAAA) {
|
||||
else if (resource.type() == AAAA) {
|
||||
v6_addr = resource.data();
|
||||
data_size = IPv6Address::address_size;
|
||||
}
|
||||
else if(contains_dname(resource.type())) {
|
||||
else if (contains_dname(resource.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;
|
||||
threshold = sections.empty() ? records_data_.size() :* sections.front().first;
|
||||
// Skip the preference field
|
||||
if(resource.type() == MX) {
|
||||
if (resource.type() == MX) {
|
||||
offset += sizeof(uint16_t);
|
||||
}
|
||||
for(size_t i = 0; i < sections.size(); ++i) {
|
||||
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,
|
||||
records_data_.insert(
|
||||
records_data_.begin() + threshold,
|
||||
offset,
|
||||
0
|
||||
);
|
||||
uint8_t *ptr = std::copy(
|
||||
buffer.begin(),
|
||||
buffer.end(),
|
||||
&records_data[0] + 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(
|
||||
static_cast<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);
|
||||
OutputMemoryStream stream(&records_data_[0] + threshold, offset);
|
||||
stream.write(buffer.begin(), buffer.end());
|
||||
stream.write_be(resource.type());
|
||||
stream.write_be(resource.query_class());
|
||||
stream.write_be(resource.ttl());
|
||||
stream.write_be<uint16_t>(data_size + (resource.type() == MX ? 2 : 0));
|
||||
if (resource.type() == MX) {
|
||||
stream.skip(sizeof(uint16_t));
|
||||
}
|
||||
if(resource.type() == A) {
|
||||
uint32_t ip_int = v4_addr;
|
||||
std::memcpy(ptr, &ip_int, sizeof(ip_int));
|
||||
if (resource.type() == A) {
|
||||
stream.write(v4_addr);
|
||||
}
|
||||
else if(resource.type() == AAAA) {
|
||||
std::copy(v6_addr.begin(), v6_addr.end(), ptr);
|
||||
else if (resource.type() == AAAA) {
|
||||
stream.write(v6_addr);
|
||||
}
|
||||
else if(!encoded_data.empty()) {
|
||||
std::copy(encoded_data.begin(), encoded_data.end(), ptr);
|
||||
else if (!encoded_data.empty()) {
|
||||
stream.write(encoded_data.begin(), encoded_data.end());
|
||||
}
|
||||
else {
|
||||
std::copy(resource.data().begin(), resource.data().end(), ptr);
|
||||
stream.write(resource.data().begin(), resource.data().end());
|
||||
}
|
||||
}
|
||||
|
||||
void DNS::add_authority(const Resource &resource) {
|
||||
void DNS::add_authority(const Resource& resource) {
|
||||
sections_type sections;
|
||||
sections.push_back(std::make_pair(&additional_idx, additional_count()));
|
||||
sections.push_back(make_pair(&additional_idx_, additional_count()));
|
||||
add_record(resource, sections);
|
||||
dns.authority = Endian::host_to_be<uint16_t>(
|
||||
header_.authority = Endian::host_to_be<uint16_t>(
|
||||
authority_count() + 1
|
||||
);
|
||||
}
|
||||
|
||||
void DNS::add_additional(const Resource &resource){
|
||||
void DNS::add_additional(const Resource& resource){
|
||||
add_record(resource, sections_type());
|
||||
dns.additional = Endian::host_to_be<uint16_t>(
|
||||
header_.additional = Endian::host_to_be<uint16_t>(
|
||||
additional_count() + 1
|
||||
);
|
||||
}
|
||||
|
||||
std::string DNS::encode_domain_name(const std::string &dn) {
|
||||
std::string output;
|
||||
string DNS::encode_domain_name(const string& dn) {
|
||||
string output;
|
||||
size_t last_index(0), index;
|
||||
if(!dn.empty()) {
|
||||
while((index = dn.find('.', last_index+1)) != string::npos) {
|
||||
if (!dn.empty()) {
|
||||
while ((index = dn.find('.', last_index+1)) != string::npos) {
|
||||
output.push_back(static_cast<char>(index - last_index));
|
||||
output.append(dn.begin() + last_index, dn.begin() + index);
|
||||
last_index = index + 1; //skip dot
|
||||
@@ -316,59 +292,64 @@ std::string DNS::encode_domain_name(const std::string &dn) {
|
||||
// The output buffer should be at least 256 bytes long. This used to use
|
||||
// a std::string but it worked about 50% slower, so this is somehow
|
||||
// unsafe but a lot faster.
|
||||
const uint8_t* DNS::compose_name(const uint8_t *ptr, char *out_ptr) const {
|
||||
const uint8_t *end = &records_data[0] + records_data.size();
|
||||
const uint8_t *end_ptr = 0;
|
||||
char *current_out_ptr = out_ptr;
|
||||
while(*ptr) {
|
||||
uint32_t DNS::compose_name(const uint8_t* ptr, char* out_ptr) const {
|
||||
const uint8_t* start_ptr = ptr;
|
||||
const uint8_t* end = &records_data_[0] + records_data_.size();
|
||||
const uint8_t* end_ptr = 0;
|
||||
char* current_out_ptr = out_ptr;
|
||||
while (*ptr) {
|
||||
// It's an offset
|
||||
if((*ptr & 0xc0)) {
|
||||
if(ptr + sizeof(uint16_t) > end)
|
||||
if ((*ptr & 0xc0)) {
|
||||
if (ptr + sizeof(uint16_t) > end) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
uint16_t index;
|
||||
std::memcpy(&index, ptr, sizeof(uint16_t));
|
||||
memcpy(&index, ptr, sizeof(uint16_t));
|
||||
index = Endian::be_to_host(index) & 0x3fff;
|
||||
// Check that the offset is neither too low or too high
|
||||
if(index < 0x0c || (&records_data[0] + (index - 0x0c)) >= end)
|
||||
if (index < 0x0c || (&records_data_[0] + (index - 0x0c)) >= end) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
// We've probably found the end of the original domain name. Save it.
|
||||
if(end_ptr == 0)
|
||||
if (end_ptr == 0) {
|
||||
end_ptr = ptr + sizeof(uint16_t);
|
||||
}
|
||||
// Now this is our pointer
|
||||
ptr = &records_data[index - 0x0c];
|
||||
ptr = &records_data_[index - 0x0c];
|
||||
}
|
||||
else {
|
||||
// It's a label, grab its size.
|
||||
uint8_t size = *ptr;
|
||||
ptr++;
|
||||
if(ptr + size > end || current_out_ptr - out_ptr + size + 1 > 255)
|
||||
if (ptr + size > end || current_out_ptr - out_ptr + size + 1 > 255) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
// Append a dot if it's not the first one.
|
||||
if(current_out_ptr != out_ptr)
|
||||
if (current_out_ptr != out_ptr) {
|
||||
*current_out_ptr++ = '.';
|
||||
std::copy(
|
||||
ptr,
|
||||
ptr + size,
|
||||
current_out_ptr
|
||||
);
|
||||
}
|
||||
copy(ptr, ptr + size, current_out_ptr);
|
||||
current_out_ptr += size;
|
||||
ptr += size;
|
||||
}
|
||||
}
|
||||
// Add the null terminator.
|
||||
*current_out_ptr = 0;
|
||||
return end_ptr ? end_ptr : (ptr + 1);
|
||||
if (!end_ptr) {
|
||||
end_ptr = ptr + 1;
|
||||
}
|
||||
return end_ptr - start_ptr;
|
||||
}
|
||||
|
||||
void DNS::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
|
||||
void DNS::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
stream.write(dns);
|
||||
stream.write(records_data.begin(), records_data.end());
|
||||
stream.write(header_);
|
||||
stream.write(records_data_.begin(), records_data_.end());
|
||||
}
|
||||
|
||||
// Optimization. Creating an IPv4Address and then using IPv4Address::to_string
|
||||
// was quite slow. The output buffer should be able to hold an IPv4 address.
|
||||
void DNS::inline_convert_v4(uint32_t value, char *output) {
|
||||
void DNS::inline_convert_v4(uint32_t value, char* output) {
|
||||
output += sprintf(
|
||||
output,
|
||||
"%d.%d.%d.%d",
|
||||
@@ -388,82 +369,62 @@ void DNS::inline_convert_v4(uint32_t value, char *output) {
|
||||
}
|
||||
|
||||
// Parses records in some section.
|
||||
void DNS::convert_records(const uint8_t *ptr, const uint8_t *end, resources_type &res) const {
|
||||
void DNS::convert_records(const uint8_t* ptr,
|
||||
const uint8_t* end,
|
||||
resources_type& res) const {
|
||||
InputMemoryStream stream(ptr, end - ptr);
|
||||
char dname[256], small_addr_buf[256];
|
||||
while(ptr < end) {
|
||||
std::string addr;
|
||||
while (stream) {
|
||||
string addr;
|
||||
bool used_small_buffer = false;
|
||||
// Retrieve the record's domain name.
|
||||
ptr = compose_name(ptr, dname);
|
||||
// 3 uint16_t fields: Type + Class + Data size
|
||||
// 1 uint32_t field: TTL
|
||||
if(ptr + sizeof(uint16_t) * 3 + sizeof(uint32_t) > end)
|
||||
throw malformed_packet();
|
||||
stream.skip(compose_name(stream.pointer(), dname));
|
||||
// Retrieve the following fields.
|
||||
uint16_t type, qclass, data_size;
|
||||
uint32_t ttl;
|
||||
std::memcpy(&type, ptr, sizeof(uint16_t)); // Type
|
||||
type = Endian::be_to_host(type);
|
||||
ptr += sizeof(uint16_t);
|
||||
std::memcpy(&qclass, ptr, sizeof(uint16_t)); // Class
|
||||
qclass = Endian::be_to_host(qclass);
|
||||
ptr += sizeof(uint16_t);
|
||||
std::memcpy(&ttl, ptr, sizeof(uint32_t)); // TTL
|
||||
ttl = Endian::be_to_host(ttl);
|
||||
ptr += sizeof(uint32_t);
|
||||
std::memcpy(&data_size, ptr, sizeof(uint16_t)); // Data size
|
||||
data_size = Endian::be_to_host(data_size);
|
||||
ptr += sizeof(uint16_t);
|
||||
type = stream.read_be<uint16_t>();
|
||||
qclass = stream.read_be<uint16_t>();
|
||||
ttl = stream.read_be<uint32_t>();
|
||||
data_size = stream.read_be<uint16_t>();
|
||||
// Skip the preference field if it's MX
|
||||
if(type == MX) {
|
||||
if(data_size < 2)
|
||||
throw malformed_packet();
|
||||
ptr += 2;
|
||||
data_size -= 2;
|
||||
if (type == MX) {
|
||||
stream.skip(sizeof(uint16_t));
|
||||
data_size -= sizeof(uint16_t);
|
||||
}
|
||||
if(ptr + data_size > end)
|
||||
if (!stream.can_read(data_size)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
switch (type) {
|
||||
case AAAA:
|
||||
if(data_size != 16)
|
||||
throw malformed_packet();
|
||||
addr = IPv6Address(ptr).to_string();
|
||||
addr = stream.read<IPv6Address>().to_string();
|
||||
break;
|
||||
case A:
|
||||
if(data_size == 4) {
|
||||
uint32_t uint32_t_buffer;
|
||||
std::memcpy(&uint32_t_buffer, ptr, sizeof(uint32_t));
|
||||
inline_convert_v4(uint32_t_buffer, small_addr_buf);
|
||||
used_small_buffer = true;
|
||||
}
|
||||
else
|
||||
throw malformed_packet();
|
||||
inline_convert_v4(stream.read<uint32_t>(), small_addr_buf);
|
||||
used_small_buffer = true;
|
||||
break;
|
||||
case NS:
|
||||
case CNAME:
|
||||
case DNAM:
|
||||
case PTR:
|
||||
case MX:
|
||||
compose_name(ptr, small_addr_buf);
|
||||
compose_name(stream.pointer(), small_addr_buf);
|
||||
stream.skip(data_size);
|
||||
used_small_buffer = true;
|
||||
break;
|
||||
default:
|
||||
if(data_size < sizeof(small_addr_buf) - 1) {
|
||||
std::copy(
|
||||
ptr,
|
||||
ptr + data_size,
|
||||
small_addr_buf
|
||||
);
|
||||
if (data_size < sizeof(small_addr_buf) - 1) {
|
||||
stream.read(small_addr_buf, data_size);
|
||||
// null terminator
|
||||
small_addr_buf[data_size] = 0;
|
||||
used_small_buffer = true;
|
||||
}
|
||||
else
|
||||
addr.assign(ptr, ptr + data_size);
|
||||
else {
|
||||
addr.assign(stream.pointer(), stream.pointer() + data_size);
|
||||
stream.skip(data_size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
ptr += data_size;
|
||||
res.push_back(
|
||||
Resource(
|
||||
dname,
|
||||
@@ -477,15 +438,15 @@ void DNS::convert_records(const uint8_t *ptr, const uint8_t *end, resources_type
|
||||
}
|
||||
|
||||
// no length checks, records should already be valid
|
||||
uint8_t *DNS::update_dname(uint8_t *ptr, uint32_t threshold, uint32_t offset) {
|
||||
while(*ptr != 0) {
|
||||
if((*ptr & 0xc0)) {
|
||||
uint8_t* DNS::update_dname(uint8_t* ptr, uint32_t threshold, uint32_t offset) {
|
||||
while (*ptr != 0) {
|
||||
if ((*ptr & 0xc0)) {
|
||||
uint16_t index;
|
||||
std::memcpy(&index, ptr, sizeof(uint16_t));
|
||||
memcpy(&index, ptr, sizeof(uint16_t));
|
||||
index = Endian::be_to_host(index) & 0x3fff;
|
||||
if(index > threshold) {
|
||||
if (index > threshold) {
|
||||
index = Endian::host_to_be<uint16_t>((index + offset) | 0xc000);
|
||||
std::memcpy(ptr, &index, sizeof(uint16_t));
|
||||
memcpy(ptr, &index, sizeof(uint16_t));
|
||||
}
|
||||
ptr += sizeof(uint16_t);
|
||||
break;
|
||||
@@ -499,24 +460,27 @@ uint8_t *DNS::update_dname(uint8_t *ptr, uint32_t threshold, uint32_t offset) {
|
||||
|
||||
// Updates offsets in domain names inside records.
|
||||
// No length checks, records are already valid.
|
||||
void DNS::update_records(uint32_t §ion_start, uint32_t num_records, uint32_t threshold, uint32_t offset) {
|
||||
if(section_start < records_data.size()) {
|
||||
uint8_t *ptr = &records_data[section_start];
|
||||
for(uint32_t i = 0; i < num_records; ++i) {
|
||||
void DNS::update_records(uint32_t& section_start,
|
||||
uint32_t num_records,
|
||||
uint32_t threshold,
|
||||
uint32_t offset) {
|
||||
if (section_start < records_data_.size()) {
|
||||
uint8_t* ptr = &records_data_[section_start];
|
||||
for (uint32_t i = 0; i < num_records; ++i) {
|
||||
ptr = update_dname(ptr, threshold, offset);
|
||||
uint16_t type;
|
||||
std::memcpy(&type, ptr, sizeof(uint16_t));
|
||||
memcpy(&type, ptr, sizeof(uint16_t));
|
||||
type = Endian::be_to_host(type);
|
||||
ptr += sizeof(uint16_t) * 2 + sizeof(uint32_t);
|
||||
uint16_t size;
|
||||
std::memcpy(&size, ptr, sizeof(uint16_t));
|
||||
memcpy(&size, ptr, sizeof(uint16_t));
|
||||
size = Endian::be_to_host(size);
|
||||
ptr += sizeof(uint16_t);
|
||||
if(type == MX) {
|
||||
if (type == MX) {
|
||||
ptr += sizeof(uint16_t);
|
||||
size -= sizeof(uint16_t);
|
||||
}
|
||||
if(contains_dname(type)) {
|
||||
if (contains_dname(type)) {
|
||||
update_dname(ptr, threshold, offset);
|
||||
}
|
||||
ptr += size;
|
||||
@@ -527,26 +491,16 @@ void DNS::update_records(uint32_t §ion_start, uint32_t num_records, uint32_t
|
||||
|
||||
DNS::queries_type DNS::queries() const {
|
||||
queries_type output;
|
||||
if(!records_data.empty()) {
|
||||
const uint8_t *ptr = &records_data[0],
|
||||
*end = &records_data[0] + answers_idx;
|
||||
if (!records_data_.empty()) {
|
||||
InputMemoryStream stream(&records_data_[0], answers_idx_);
|
||||
char buffer[256];
|
||||
uint16_t tmp_query_type;
|
||||
uint16_t tmp_query_class;
|
||||
while(ptr < end) {
|
||||
ptr = compose_name(ptr, buffer);
|
||||
if(ptr + sizeof(uint16_t) * 2 > end)
|
||||
throw malformed_packet();
|
||||
std::memcpy(&tmp_query_type, ptr, sizeof(uint16_t));
|
||||
std::memcpy(&tmp_query_class, ptr + 2, sizeof(uint16_t));
|
||||
while (stream) {
|
||||
stream.skip(compose_name(stream.pointer(), buffer));
|
||||
uint16_t query_type = stream.read_be<uint16_t>();
|
||||
uint16_t query_class = stream.read_be<uint16_t>();
|
||||
output.push_back(
|
||||
Query(
|
||||
buffer,
|
||||
(QueryType)Endian::be_to_host(tmp_query_type),
|
||||
(QueryClass)Endian::be_to_host(tmp_query_class)
|
||||
)
|
||||
Query(buffer, (QueryType)query_type, (QueryClass)query_class)
|
||||
);
|
||||
ptr += sizeof(uint16_t) * 2;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
@@ -554,10 +508,10 @@ DNS::queries_type DNS::queries() const {
|
||||
|
||||
DNS::resources_type DNS::answers() const {
|
||||
resources_type res;
|
||||
if(answers_idx < records_data.size()) {
|
||||
if (answers_idx_ < records_data_.size()) {
|
||||
convert_records(
|
||||
&records_data[0] + answers_idx,
|
||||
&records_data[0] + authority_idx,
|
||||
&records_data_[0] + answers_idx_,
|
||||
&records_data_[0] + authority_idx_,
|
||||
res
|
||||
);
|
||||
}
|
||||
@@ -566,10 +520,10 @@ DNS::resources_type DNS::answers() const {
|
||||
|
||||
DNS::resources_type DNS::authority() const {
|
||||
resources_type res;
|
||||
if(authority_idx < records_data.size()) {
|
||||
if (authority_idx_ < records_data_.size()) {
|
||||
convert_records(
|
||||
&records_data[0] + authority_idx,
|
||||
&records_data[0] + additional_idx,
|
||||
&records_data_[0] + authority_idx_,
|
||||
&records_data_[0] + additional_idx_,
|
||||
res
|
||||
);
|
||||
}
|
||||
@@ -578,20 +532,22 @@ DNS::resources_type DNS::authority() const {
|
||||
|
||||
DNS::resources_type DNS::additional() const {
|
||||
resources_type res;
|
||||
if(additional_idx < records_data.size()) {
|
||||
if (additional_idx_ < records_data_.size()) {
|
||||
convert_records(
|
||||
&records_data[0] + additional_idx,
|
||||
&records_data[0] + records_data.size(),
|
||||
&records_data_[0] + additional_idx_,
|
||||
&records_data_[0] + records_data_.size(),
|
||||
res
|
||||
);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool DNS::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
if(total_sz < sizeof(dnshdr))
|
||||
bool DNS::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
if (total_sz < sizeof(header_)) {
|
||||
return false;
|
||||
const dnshdr *hdr = (const dnshdr*)ptr;
|
||||
return hdr->id == dns.id;
|
||||
}
|
||||
}
|
||||
const dns_header* hdr = (const dns_header*)ptr;
|
||||
return hdr->id == header_.id;
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
Reference in New Issue
Block a user