diff --git a/depends.d b/depends.d index 8e50536..257d3a4 100644 --- a/depends.d +++ b/depends.d @@ -66,7 +66,7 @@ include/ethernetII.h: include/network_interface.h: src/dns.o: src/dns.cpp include/dns.h include/pdu.h include/endianness.h \ - include/ip_address.h + include/dns_record.h include/ip_address.h include/dns.h: @@ -74,7 +74,15 @@ include/pdu.h: include/endianness.h: +include/dns_record.h: + include/ip_address.h: +src/dns_record.o: src/dns_record.cpp include/dns_record.h \ + include/endianness.h + +include/dns_record.h: + +include/endianness.h: src/dot11.o: src/dot11.cpp include/dot11.h include/pdu.h \ include/endianness.h include/hw_address.h include/small_uint.h \ include/pdu_option.h include/network_interface.h include/ip_address.h \ @@ -450,8 +458,8 @@ include/rawpdu.h: src/utils.o: src/utils.cpp include/utils.h include/ip_address.h \ include/hw_address.h include/pdu.h include/ip.h include/pdu.h \ include/small_uint.h include/endianness.h include/pdu_option.h \ - include/icmp.h include/arp.h include/endianness.h \ - include/network_interface.h include/packet_sender.h + include/arp.h include/endianness.h include/network_interface.h \ + include/packet_sender.h include/utils.h: @@ -471,8 +479,6 @@ include/endianness.h: include/pdu_option.h: -include/icmp.h: - include/arp.h: include/endianness.h: diff --git a/include/dns.h b/include/dns.h index 2db1b7e..9848e0b 100644 --- a/include/dns.h +++ b/include/dns.h @@ -30,6 +30,7 @@ #include #include "pdu.h" #include "endianness.h" +#include "dns_record.h" namespace Tins { class IPv4Address; @@ -152,11 +153,6 @@ namespace Tins { */ DNS(); - /** - * \brief Destructor. - */ - ~DNS(); - /** * \brief Constructor which creates a DNS object from a buffer * and adds all identifiable PDUs found in the buffer as @@ -167,16 +163,6 @@ namespace Tins { */ DNS(const uint8_t *buffer, uint32_t total_sz); - /** - * \brief Copy constructor. - */ - DNS(const DNS& rhs); - - /** - * \brief Copy assignment operator. - */ - DNS& operator=(const DNS& rhs); - // Getters /** @@ -518,81 +504,12 @@ namespace Tins { authority, additional; } __attribute__((packed)); - struct ResourceRecord { - struct Info { - uint16_t type, qclass; - uint32_t ttl; - } __attribute__((packed)) info; - - std::vector data; - - ResourceRecord(const uint8_t *d = 0, uint16_t len = 0) { - if(d && len) - data.assign(d, d + len); - } - - virtual ~ResourceRecord() {} - virtual ResourceRecord *clone() const = 0; - uint32_t write(uint8_t *buffer) const; - virtual uint32_t do_write(uint8_t *buffer) const = 0; - virtual uint32_t size() const = 0; - virtual bool matches(const std::string &dname) { return false; } - uint32_t data_size() const { - return data.size(); - } - const uint8_t *data_pointer() const { - return &data[0]; - } - virtual const std::string *dname_pointer() const { return 0; } - }; - - struct OffsetedResourceRecord : public ResourceRecord { - uint16_t offset; - - OffsetedResourceRecord(uint16_t off, const uint8_t *data = 0, uint16_t len = 0) - : ResourceRecord(data,len), offset(off | 0xc0) {} - - uint32_t do_write(uint8_t *buffer) const { - std::memcpy(buffer, &offset, sizeof(offset)); - return sizeof(offset); - } - uint32_t size() const { - return sizeof(ResourceRecord::info) + sizeof(offset) + data.size() + sizeof(uint16_t); - } - ResourceRecord *clone() const; - }; - - struct NamedResourceRecord : public ResourceRecord { - std::string name; - - NamedResourceRecord(const std::string &nm, const uint8_t *data = 0, uint16_t len = 0) - : ResourceRecord(data,len), name(nm) {} - - uint32_t do_write(uint8_t *buffer) const { - std::memcpy(buffer, name.c_str(), name.size() + 1); - return name.size() + 1; - } - - uint32_t size() const { - return sizeof(ResourceRecord::info) + name.size() + 1 + data.size() + sizeof(uint16_t); - } - - bool matches(const std::string &dname) { - return dname == name; - } - - const std::string *dname_pointer() const { - return &name; - } - ResourceRecord *clone() const; - }; - typedef std::map SuffixMap; typedef std::map SuffixIndices; - typedef std::list ResourcesType; + typedef std::list ResourcesType; typedef std::list QueriesType; - const uint8_t *build_resource_list(std::list &lst, const uint8_t *ptr, uint32_t &sz, uint16_t nrecs); + const uint8_t *build_resource_list(ResourcesType &lst, const uint8_t *ptr, uint32_t &sz, uint16_t nrecs); uint32_t find_domain_name(const std::string &dname); bool find_domain_name(const std::string &dname, const ResourcesType &lst, uint16_t &out); void parse_domain_name(const std::string &dn, std::string &out) const; @@ -601,23 +518,19 @@ namespace Tins { uint8_t *serialize_list(const ResourcesType &lst, uint8_t *buffer) const; void compose_name(const uint8_t *ptr, uint32_t sz, std::string &out); void convert_resources(const ResourcesType &lst, std::list &res); - ResourceRecord *make_record(const std::string &name, QueryType type, QueryClass qclass, uint32_t ttl, uint32_t ip); - ResourceRecord *make_record(const std::string &name, QueryType type, QueryClass qclass, uint32_t ttl, const std::string &dname); - ResourceRecord *make_record(const std::string &name, QueryType type, QueryClass qclass, uint32_t ttl, const uint8_t *ptr, uint32_t len); + DNSResourceRecord make_record(const std::string &name, QueryType type, QueryClass qclass, uint32_t ttl, uint32_t ip); + DNSResourceRecord make_record(const std::string &name, QueryType type, QueryClass qclass, uint32_t ttl, const std::string &dname); + DNSResourceRecord make_record(const std::string &name, QueryType type, QueryClass qclass, uint32_t ttl, const uint8_t *ptr, uint32_t len); void add_suffix(uint32_t index, const uint8_t *data, uint32_t sz); uint32_t build_suffix_map(uint32_t index, const ResourcesType &lst); uint32_t build_suffix_map(uint32_t index, const QueriesType &lst); void build_suffix_map(); - void copy_list(const ResourcesType &from, ResourcesType &to) const; bool contains_dname(uint16_t type); - void free_list(ResourcesType &lst); - - void copy_fields(const DNS *other); dnshdr dns; uint32_t extra_size; std::list queries; - std::list ans, arity, addit; + ResourcesType ans, arity, addit; SuffixMap suffixes; SuffixIndices suffix_indices; }; diff --git a/include/dns_record.h b/include/dns_record.h new file mode 100644 index 0000000..414c854 --- /dev/null +++ b/include/dns_record.h @@ -0,0 +1,231 @@ +/* + * libtins is a net packet wrapper library for crafting and + * interpreting sniffed packets. + * + * Copyright (C) 2011 Nasel + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef TINS_DNS_RECORD_H +#define TINS_DNS_RECORD_H + +#include +#include +#include + +namespace Tins { +class DNSRRImpl; + +/** + * \brief Abstracts a DNS resource record. + */ +class DNSResourceRecord { +public: + /** + * \brief The type used to store resource records' information. + */ + struct Info { + uint16_t type, qclass; + uint32_t ttl; + } __attribute__((packed)); + + /** + * \brief Constructs a record. + * \param impl A pointer to the impl object. + * \param data A pointer to the start of the data buffer. + * \param len The length of the data. + */ + DNSResourceRecord(DNSRRImpl *impl = 0, const uint8_t *data = 0, uint16_t len = 0); + + /** + * \brief Constructs a record. + * \param buffer A pointer to the start of the data buffer. + * \param len The length of the data. + */ + DNSResourceRecord(const uint8_t *buffer, uint32_t size); + + /** + * \brief Constructs a record from an input range. + * \param impl A pointer to the impl object. + * \param start The begining of the range. + * \param end The end of the range. + */ + template + DNSResourceRecord(DNSRRImpl *impl, ForwardIterator start, ForwardIterator end) + : impl(impl), data(start, end) + { } + + /** + * \brief Copy constructor. + * + * This handles cloning the impl object. + * \param rhs The record which will be copied. + */ + DNSResourceRecord(const DNSResourceRecord &rhs); + + /** + * \brief Copy assignment operator. + * + * This handles cloning the impl object. + * \param rhs The record which will be copied. + */ + DNSResourceRecord& operator=(const DNSResourceRecord &rhs); + + /** + * \brief Destructor. + * + * This frees the impl object. + */ + ~DNSResourceRecord(); + + /** + * \brief Writes this record to a buffer. + * + * \param buffer The buffer in which to store the serialization. + * \return uint32_t containing the number of bytes written. + */ + uint32_t write(uint8_t *buffer) const; + + /** + * \brief Returns the size of the data in this record. + */ + uint32_t data_size() const { + return data.size(); + } + + /** + * \brief Returns the pointer to the start of the data buffer. + */ + const uint8_t *data_ptr() const { + return &data[0]; + } + + /** + * \brief Returns a bool indicating whether this record contains + * a domain name as the name being resolved. + */ + bool has_domain_name() const; + + /** + * \brief Returns a pointer to the domain name stored in this record. + * + * This will throw a std::bad_cast exception if the impl object is + * not of the type NamedDNSRRImpl. + */ + const std::string *dname() const; + + /** + * \brief Returns the offset stored in this record. + * + * This will throw a std::bad_cast exception if the impl object is + * not of the type OffsetedDNSRRImpl. + */ + uint16_t offset() const; + + /** + * \brief Returns the size of this record. + */ + uint32_t size() const; + + /** + * \brief Returns a reference to the info field. + */ + Info &info() { + return info_; + } + + /** + * \brief Returns a const reference to the info field. + */ + const Info &info() const { + return info_; + } + + /** + * \brief Checks if the domain name stored in this record matches + * the given one. + * + * This is a shortcut + */ + bool matches(const std::string &dname) const; +private: + DNSRRImpl *clone_impl() const; + size_t impl_size() const; + + Info info_; + std::vector data; + DNSRRImpl *impl; +}; + +/** + * \cond + */ +class DNSRRImpl { +public: + virtual ~DNSRRImpl() {} + virtual uint32_t size() const = 0; + virtual uint32_t do_write(uint8_t *buffer) const = 0; + virtual bool matches(const std::string &dname) const { return false; } + virtual DNSRRImpl *clone() const = 0; +}; + +class OffsetedDNSRRImpl : public DNSRRImpl { +public: + OffsetedDNSRRImpl(uint16_t off); + + uint32_t do_write(uint8_t *buffer) const; + uint32_t size() const; + OffsetedDNSRRImpl *clone() const; + uint16_t offset() const; +private: + uint16_t offset_; +}; + +class NamedDNSRRImpl : public DNSRRImpl { +public: + NamedDNSRRImpl(const std::string &nm); + + template + NamedDNSRRImpl(ForwardIterator start, ForwardIterator end) + : name(start, end) + { } + + uint32_t do_write(uint8_t *buffer) const; + + uint32_t size() const; + + bool matches(const std::string &dname) const; + + const std::string *dname_pointer() const; + NamedDNSRRImpl *clone() const; +private: + std::string name; +}; + +/** + * \endcond + */ + +inline DNSResourceRecord make_offseted_record(uint16_t offset, const uint8_t *data = 0, uint32_t size = 0) { + return DNSResourceRecord(new OffsetedDNSRRImpl(offset), data, size); +} + +inline DNSResourceRecord make_named_record(const std::string &name, const uint8_t *data = 0, uint32_t size = 0) { + return DNSResourceRecord(new NamedDNSRRImpl(name), data, size); +} +} + +#endif // TINS_DNS_RECORD_H diff --git a/src/dns.cpp b/src/dns.cpp index 0c44b8a..52d2f51 100644 --- a/src/dns.cpp +++ b/src/dns.cpp @@ -65,81 +65,17 @@ DNS::DNS(const uint8_t *buffer, uint32_t total_sz) : PDU(255), extra_size(0) { build_resource_list(addit, buffer, total_sz, additional()); } -DNS::DNS(const DNS& rhs) : PDU(rhs) { - copy_fields(&rhs); -} - -DNS& DNS::operator=(const DNS& rhs) { - free_list(ans); - free_list(arity); - free_list(addit); - copy_fields(&rhs); - copy_inner_pdu(rhs); - return *this; -} - -DNS::~DNS() { - free_list(ans); - free_list(arity); - free_list(addit); -} - -void DNS::free_list(ResourcesType &lst) { - while(lst.size()) { - delete lst.front(); - lst.pop_front(); - } -} - -const uint8_t *DNS::build_resource_list(list &lst, const uint8_t *ptr, uint32_t &sz, uint16_t nrecs) { +const uint8_t *DNS::build_resource_list(ResourcesType &lst, const uint8_t *ptr, uint32_t &sz, uint16_t nrecs) { const uint8_t *ptr_end(ptr + sz); const uint8_t *parse_start(ptr); for(uint16_t i(0); i < nrecs; ++i) { const uint8_t *this_opt_start(ptr); if(ptr + sizeof(uint16_t) > ptr_end) throw std::runtime_error("Not enough size for a given resource."); - std::auto_ptr res; - // Probably convert to be this constant - if((*ptr & 0xc0)) { - uint16_t offset(*reinterpret_cast(ptr)); - offset = Endian::be_to_host(offset) & 0x3fff; - res.reset(new OffsetedResourceRecord(Endian::host_to_be(offset))); - ptr += sizeof(uint16_t); - } - else { - const uint8_t *str_end(ptr); - while(str_end < ptr_end && *str_end) - str_end++; - if(str_end == ptr_end) - throw std::runtime_error("Not enough size for a resource domain name."); - //str_end++; - res.reset(new NamedResourceRecord(string(ptr, str_end))); - ptr = ++str_end; - } - if(ptr + sizeof(res->info) > ptr_end) - throw std::runtime_error("Not enough size for a resource info."); - std::memcpy(&res->info, ptr, sizeof(res->info)); - ptr += sizeof(res->info); - if(ptr + sizeof(uint16_t) > ptr_end) - throw std::runtime_error("Not enough size for resource data size."); - - // Store the option size. - res->data.resize( - Endian::be_to_host(*reinterpret_cast(ptr)) - ); - ptr += sizeof(uint16_t); - if(ptr + res->data.size() > ptr_end) - throw std::runtime_error("Not enough size for resource data"); - if(contains_dname(res->info.type)) - std::copy(ptr, ptr + res->data.size(), res->data.begin()); - else if(res->data.size() == sizeof(uint32_t)) - *(uint32_t*)&res->data[0] = *(uint32_t*)ptr; - else - throw std::runtime_error("Not enough size for resource data"); - - ptr += res->data.size(); + lst.push_back(DNSResourceRecord(ptr, ptr_end - ptr)); + ptr += lst.back().size(); extra_size += ptr - this_opt_start; - lst.push_back(res.release()); + } sz -= ptr - parse_start; return ptr; @@ -221,8 +157,7 @@ void DNS::add_query(const Query &query) { } void DNS::add_answer(const string &name, QueryType type, QueryClass qclass, uint32_t ttl, IPv4Address ip) { - ResourceRecord *res = make_record(name, type, qclass, ttl, Endian::host_to_be((uint32_t)ip)); - ans.push_back(res); + ans.push_back(make_record(name, type, qclass, ttl, Endian::host_to_be((uint32_t)ip))); dns.answers = Endian::host_to_be(ans.size()); } @@ -230,53 +165,50 @@ void DNS::add_answer(const std::string &name, QueryType type, QueryClass qclass, uint32_t ttl, const std::string &dname) { string new_str; parse_domain_name(dname, new_str); - ResourceRecord *res = make_record(name, type, qclass, ttl, new_str); + DNSResourceRecord res = make_record(name, type, qclass, ttl, new_str); ans.push_back(res); dns.answers = Endian::host_to_be(ans.size()); } void DNS::add_answer(const std::string &name, QueryType type, QueryClass qclass, uint32_t ttl, const uint8_t *data, uint32_t sz) { - ResourceRecord *res = make_record(name, type, qclass, ttl, data, sz); - ans.push_back(res); + ans.push_back(make_record(name, type, qclass, ttl, data, sz)); dns.answers = Endian::host_to_be(ans.size()); } void DNS::add_authority(const string &name, QueryType type, QueryClass qclass, uint32_t ttl, const uint8_t *data, uint32_t sz) { - ResourceRecord *res = make_record(name, type, qclass, ttl, data, sz); - arity.push_back(res); + arity.push_back(make_record(name, type, qclass, ttl, data, sz)); dns.authority = Endian::host_to_be(arity.size()); } void DNS::add_additional(const string &name, QueryType type, QueryClass qclass, uint32_t ttl, uint32_t ip) { - ResourceRecord *res = make_record(name, type, qclass, ttl, ip); - addit.push_back(res); + addit.push_back(make_record(name, type, qclass, ttl, ip)); dns.additional = Endian::host_to_be(addit.size()); } -DNS::ResourceRecord *DNS::make_record(const std::string &name, QueryType type, QueryClass qclass, uint32_t ttl, uint32_t ip) { +DNSResourceRecord DNS::make_record(const std::string &name, QueryType type, QueryClass qclass, uint32_t ttl, uint32_t ip) { ip = Endian::host_to_be(ip); return make_record(name, type, qclass, ttl, reinterpret_cast(&ip), sizeof(ip)); } -DNS::ResourceRecord *DNS::make_record(const std::string &name, QueryType type, QueryClass qclass, uint32_t ttl, const std::string &dname) { +DNSResourceRecord DNS::make_record(const std::string &name, QueryType type, QueryClass qclass, uint32_t ttl, const std::string &dname) { return make_record(name, type, qclass, ttl, reinterpret_cast(dname.c_str()), dname.size() + 1); } -DNS::ResourceRecord *DNS::make_record(const std::string &name, QueryType type, QueryClass qclass, uint32_t ttl, const uint8_t *ptr, uint32_t len) { +DNSResourceRecord DNS::make_record(const std::string &name, QueryType type, QueryClass qclass, uint32_t ttl, const uint8_t *ptr, uint32_t len) { string nm; parse_domain_name(name, nm); uint16_t index = find_domain_name(nm); - ResourceRecord *res; + DNSResourceRecord res; if(index) - res = new OffsetedResourceRecord(Endian::host_to_be(index), ptr, len); + res = make_offseted_record(Endian::host_to_be(index), ptr, len); else - res = new NamedResourceRecord(nm, ptr, len); - res->info.type = Endian::host_to_be(type); - res->info.qclass = Endian::host_to_be(qclass); - res->info.ttl = Endian::host_to_be(ttl); - extra_size += res->size(); + res = make_named_record(nm, ptr, len); + res.info().type = Endian::host_to_be(type); + res.info().qclass = Endian::host_to_be(qclass); + res.info().ttl = Endian::host_to_be(ttl); + extra_size += res.size(); return res; } @@ -297,9 +229,9 @@ uint32_t DNS::find_domain_name(const std::string &dname) { bool DNS::find_domain_name(const std::string &dname, const ResourcesType &lst, uint16_t &out) { ResourcesType::const_iterator it(lst.begin()); while(it != lst.end()) { - if((*it)->matches(dname)) + if(it->matches(dname)) break; - out += (*it)->size(); + out += it->size(); ++it; } return it != lst.end(); @@ -354,7 +286,7 @@ void DNS::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *par uint8_t *DNS::serialize_list(const ResourcesType &lst, uint8_t *buffer) const { for(ResourcesType::const_iterator it(lst.begin()); it != lst.end(); ++it) - buffer += (*it)->write(buffer); + buffer += it->write(buffer); return buffer; } @@ -377,25 +309,25 @@ void DNS::add_suffix(uint32_t index, const uint8_t *data, uint32_t sz) { } } -uint32_t DNS::build_suffix_map(uint32_t index, const list &lst) { +uint32_t DNS::build_suffix_map(uint32_t index, const ResourcesType &lst) { const string *str; for(ResourcesType::const_iterator it(lst.begin()); it != lst.end(); ++it) { - str = (*it)->dname_pointer(); + str = it->dname(); if(str) { add_suffix(index, (uint8_t*)str->c_str(), str->size()); index += str->size() + 1; } else index += sizeof(uint16_t); - index += sizeof(ResourceRecord::Info) + sizeof(uint16_t); - uint32_t sz((*it)->data_size()); - const uint8_t *ptr = (*it)->data_pointer(); - if(Endian::be_to_host((*it)->info.type) == MX) { + index += sizeof(DNSResourceRecord::Info) + sizeof(uint16_t); + uint32_t sz(it->data_size()); + const uint8_t *ptr = it->data_ptr(); + if(Endian::be_to_host(it->info().type) == MX) { ptr += 2; sz -= 2; index += 2; } - if(contains_dname((*it)->info.type)) + if(contains_dname(it->info().type)) add_suffix(index, ptr, sz); index += sz; } @@ -467,26 +399,26 @@ void DNS::convert_resources(const ResourcesType &lst, std::list &res) uint32_t sz; for(ResourcesType::const_iterator it(lst.begin()); it != lst.end(); ++it) { string dname, addr; - if((str_ptr = (*it)->dname_pointer())) + if(it->has_domain_name() && (str_ptr = it->dname())) compose_name(reinterpret_cast(str_ptr->c_str()), str_ptr->size(), dname); else { - uint16_t offset = static_cast(*it)->offset; + uint16_t offset = it->offset(); compose_name((uint8_t*)&offset, 2, dname); } - ptr = (*it)->data_pointer(); - sz = (*it)->data_size(); + ptr = it->data_ptr(); + sz = it->data_size(); if(sz == 4) addr = IPv4Address(*(uint32_t*)ptr).to_string(); else { - if(Endian::be_to_host((*it)->info.type) == MX) { + if(Endian::be_to_host(it->info().type) == MX) { ptr += 2; sz -= 2; } compose_name(ptr, sz, addr); } res.push_back( - Resource(dname, addr, Endian::be_to_host((*it)->info.type), - Endian::host_to_be((*it)->info.qclass), Endian::be_to_host((*it)->info.ttl) + Resource(dname, addr, Endian::be_to_host(it->info().type), + Endian::host_to_be(it->info().qclass), Endian::be_to_host(it->info().ttl) ) ); } @@ -507,40 +439,4 @@ DNS::resources_type DNS::dns_answers() { convert_resources(ans, res); return res; } - -void DNS::copy_fields(const DNS *other) { - std::memcpy(&dns, &other->dns, sizeof(dns)); - extra_size = other->extra_size; - queries = other->queries; - copy_list(other->ans, ans); - copy_list(other->arity, arity); - copy_list(other->addit, addit); -} - -void DNS::copy_list(const ResourcesType &from, ResourcesType &to) const { - for(ResourcesType::const_iterator it(from.begin()); it != from.end(); ++it) { - to.push_back((*it)->clone()); - } -} - -// ResourceRecord - -uint32_t DNS::ResourceRecord::write(uint8_t *buffer) const { - const uint32_t sz(do_write(buffer)); - buffer += sz; - std::memcpy(buffer, &info, sizeof(info)); - buffer += sizeof(info); - *((uint16_t*)buffer) = Endian::host_to_be(data.size()); - buffer += sizeof(uint16_t); - std::copy(data.begin(), data.end(), buffer); - return sz + sizeof(info) + sizeof(uint16_t) + data.size(); -} - -DNS::ResourceRecord *DNS::OffsetedResourceRecord::clone() const { - return new OffsetedResourceRecord(*this); -} - -DNS::ResourceRecord *DNS::NamedResourceRecord::clone() const { - return new NamedResourceRecord(*this); -} } diff --git a/src/dns_record.cpp b/src/dns_record.cpp new file mode 100644 index 0000000..84550a6 --- /dev/null +++ b/src/dns_record.cpp @@ -0,0 +1,199 @@ +/* + * libtins is a net packet wrapper library for crafting and + * interpreting sniffed packets. + * + * Copyright (C) 2011 Nasel + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include "dns_record.h" +#include "endianness.h" + +namespace Tins { +bool contains_dname(uint16_t type) { + type = Endian::be_to_host(type); + return type == 15 || type == 5 || + type == 12 || type == 2; +} + +DNSResourceRecord::DNSResourceRecord(DNSRRImpl *impl, + const uint8_t *d, uint16_t len) : impl(impl) +{ + if(d && len) + data.assign(d, d + len); +} + +DNSResourceRecord::DNSResourceRecord(const uint8_t *buffer, uint32_t size) +{ + const uint8_t *buffer_end = buffer + size; + if((*buffer & 0xc0)) { + uint16_t offset(*reinterpret_cast(buffer)); + offset = Endian::be_to_host(offset) & 0x3fff; + impl = new OffsetedDNSRRImpl(Endian::host_to_be(offset)); + buffer += sizeof(uint16_t); + } + else { + const uint8_t *str_end(buffer); + while(str_end < buffer_end && *str_end) + str_end++; + if(str_end == buffer_end) + throw std::runtime_error("Not enough size for a resource domain name."); + //str_end++; + impl = new NamedDNSRRImpl(buffer, str_end); + buffer = ++str_end; + } + if(buffer + sizeof(info_) > buffer_end) + throw std::runtime_error("Not enough size for a resource info."); + std::memcpy(&info_, buffer, sizeof(info_)); + buffer += sizeof(info_); + if(buffer + sizeof(uint16_t) > buffer_end) + throw std::runtime_error("Not enough size for resource data size."); + + // Store the option size. + data.resize( + Endian::be_to_host(*reinterpret_cast(buffer)) + ); + buffer += sizeof(uint16_t); + if(buffer + data.size() > buffer_end) + throw std::runtime_error("Not enough size for resource data"); + if(contains_dname(info_.type)) + std::copy(buffer, buffer + data.size(), data.begin()); + else if(data.size() == sizeof(uint32_t)) + *(uint32_t*)&data[0] = *(uint32_t*)buffer; + else + throw std::runtime_error("Not enough size for resource data"); +} + +DNSResourceRecord::DNSResourceRecord(const DNSResourceRecord &rhs) +: info_(rhs.info_), data(rhs.data), impl(rhs.clone_impl()) +{ + +} + +DNSResourceRecord& DNSResourceRecord::operator=(const DNSResourceRecord &rhs) +{ + delete impl; + info_ = rhs.info_; + data = rhs.data; + impl = rhs.clone_impl(); + return *this; +} + +DNSResourceRecord::~DNSResourceRecord() { + delete impl; +} + +uint32_t DNSResourceRecord::write(uint8_t *buffer) const { + const uint32_t sz(impl ? impl->do_write(buffer) : 0); + buffer += sz; + std::memcpy(buffer, &info_, sizeof(info_)); + buffer += sizeof(info_); + *((uint16_t*)buffer) = Endian::host_to_be(data.size()); + buffer += sizeof(uint16_t); + std::copy(data.begin(), data.end(), buffer); + return sz + sizeof(info_) + sizeof(uint16_t) + data.size(); +} + +DNSRRImpl *DNSResourceRecord::clone_impl() const { + return impl ? impl->clone() : 0; +} + +bool DNSResourceRecord::has_domain_name() const { + if(!impl) + throw std::bad_cast(); + return dynamic_cast(impl) != 0; +} + +const std::string *DNSResourceRecord::dname() const { + if(!impl) + throw std::bad_cast(); + return dynamic_cast(*impl).dname_pointer(); +} + +uint16_t DNSResourceRecord::offset() const { + return dynamic_cast(*impl).offset(); +} + +size_t DNSResourceRecord::impl_size() const { + return impl ? impl->size() : 0; +} + +uint32_t DNSResourceRecord::size() const { + return sizeof(info_) + data.size() + sizeof(uint16_t) + impl_size(); +} + +bool DNSResourceRecord::matches(const std::string &dname) const { + return impl ? impl->matches(dname) : false; +} + +// OffsetedRecord + +OffsetedDNSRRImpl::OffsetedDNSRRImpl(uint16_t off) +: offset_(off | 0xc0) +{ + +} + +uint32_t OffsetedDNSRRImpl::do_write(uint8_t *buffer) const { + std::memcpy(buffer, &offset_, sizeof(offset_)); + return sizeof(offset_); +} + +uint32_t OffsetedDNSRRImpl::size() const { + return sizeof(offset_); +} + +OffsetedDNSRRImpl *OffsetedDNSRRImpl::clone() const { + return new OffsetedDNSRRImpl(*this); +} + +uint16_t OffsetedDNSRRImpl::offset() const { + return offset_; +} + +// NamedRecord + +NamedDNSRRImpl::NamedDNSRRImpl(const std::string &nm) +: name(nm) +{ + +} + +uint32_t NamedDNSRRImpl::size() const { + return name.size() + 1; +} + +uint32_t NamedDNSRRImpl::do_write(uint8_t *buffer) const { + std::copy(name.begin(), name.end() + 1, buffer); + return name.size() + 1; +} + +const std::string *NamedDNSRRImpl::dname_pointer() const { + return &name; +} + +bool NamedDNSRRImpl::matches(const std::string &dname) const { + return dname == name; +} + +NamedDNSRRImpl *NamedDNSRRImpl::clone() const { + return new NamedDNSRRImpl(*this); +} + +} diff --git a/tests/depends.d b/tests/depends.d index 0418448..5a4d8a8 100644 --- a/tests/depends.d +++ b/tests/depends.d @@ -45,8 +45,8 @@ src/dhcp.o: src/dhcp.cpp ../include/dhcp.h ../include/bootp.h \ ../include/ip_address.h: src/dns.o: src/dns.cpp ../include/dns.h ../include/pdu.h \ - ../include/endianness.h ../include/utils.h ../include/ip_address.h \ - ../include/hw_address.h + ../include/endianness.h ../include/dns_record.h ../include/utils.h \ + ../include/ip_address.h ../include/hw_address.h ../include/dns.h: @@ -54,6 +54,8 @@ src/dns.o: src/dns.cpp ../include/dns.h ../include/pdu.h \ ../include/endianness.h: +../include/dns_record.h: + ../include/utils.h: ../include/ip_address.h: @@ -728,7 +730,7 @@ include/tests/dot11.h: ../include/network_interface.h: ../src/dns.o: ../src/dns.cpp ../include/dns.h ../include/pdu.h \ - ../include/endianness.h ../include/ip_address.h + ../include/endianness.h ../include/dns_record.h ../include/ip_address.h ../include/dns.h: @@ -736,7 +738,15 @@ include/tests/dot11.h: ../include/endianness.h: +../include/dns_record.h: + ../include/ip_address.h: +../src/dns_record.o: ../src/dns_record.cpp ../include/dns_record.h \ + ../include/endianness.h + +../include/dns_record.h: + +../include/endianness.h: ../src/dot11.o: ../src/dot11.cpp ../include/dot11.h ../include/pdu.h \ ../include/endianness.h ../include/hw_address.h ../include/small_uint.h \ ../include/pdu_option.h ../include/network_interface.h \ @@ -1120,8 +1130,8 @@ include/tests/dot11.h: ../src/utils.o: ../src/utils.cpp ../include/utils.h \ ../include/ip_address.h ../include/hw_address.h ../include/pdu.h \ ../include/ip.h ../include/pdu.h ../include/small_uint.h \ - ../include/endianness.h ../include/pdu_option.h ../include/icmp.h \ - ../include/arp.h ../include/endianness.h ../include/network_interface.h \ + ../include/endianness.h ../include/pdu_option.h ../include/arp.h \ + ../include/endianness.h ../include/network_interface.h \ ../include/packet_sender.h ../include/utils.h: @@ -1142,8 +1152,6 @@ include/tests/dot11.h: ../include/pdu_option.h: -../include/icmp.h: - ../include/arp.h: ../include/endianness.h: