diff --git a/include/dns.h b/include/dns.h index cda491a..074ac2a 100644 --- a/include/dns.h +++ b/include/dns.h @@ -42,6 +42,7 @@ namespace Tins { class IPv4Address; + class IPv6Address; /** * \class DNS @@ -240,6 +241,7 @@ namespace Tins { typedef std::list queries_type; typedef std::list resources_type; typedef IPv4Address address_type; + typedef IPv6Address address_v6_type; /** * \brief Default constructor. @@ -485,6 +487,18 @@ namespace Tins { */ void add_answer(const std::string &name, const DNSResourceRecord::info &info, address_type ip); + + /** + * \brief Add a query response. + * + * \param name The resolved name. + * \param type The type of this answer. + * \param qclass The class of this answer. + * \param ttl The time-to-live of this answer. + * \param ip The ip address of the resolved name. + */ + void add_answer(const std::string &name, + const DNSResourceRecord::info &info, address_v6_type ip); /** * \brief Add a query response. diff --git a/include/ipv6_address.h b/include/ipv6_address.h index 0f6db36..e9665f2 100644 --- a/include/ipv6_address.h +++ b/include/ipv6_address.h @@ -72,6 +72,15 @@ public: */ IPv6Address(const std::string &addr); + /** + * \brief Constructor from a buffer. + * + * The ptr parameter must be at least address_size bytes long. + * + * \param ptr The buffer from which to construct this object. + */ + IPv6Address(const_iterator ptr); + /** * \brief Retrieve the string representation of this address. * diff --git a/src/dns.cpp b/src/dns.cpp index d27cd1e..ab22463 100644 --- a/src/dns.cpp +++ b/src/dns.cpp @@ -34,6 +34,7 @@ #include #include "dns.h" #include "ip_address.h" +#include "ipv6_address.h" using std::string; using std::list; @@ -166,6 +167,13 @@ void DNS::add_answer(const string &name, const DNSResourceRecord::info &info, dns.answers = Endian::host_to_be(ans.size()); } +void DNS::add_answer(const string &name, const DNSResourceRecord::info &info, + address_v6_type ip) +{ + ans.push_back(make_record(name, info, ip.begin(), address_v6_type::address_size)); + dns.answers = Endian::host_to_be(ans.size()); +} + void DNS::add_answer(const std::string &name, const DNSResourceRecord::info &info, const std::string &dname) { @@ -433,14 +441,7 @@ void DNS::convert_resources(const ResourcesType &lst, std::list &res) if(Endian::be_to_host(it->information().type) == DNS::AAAA) { if(sz != 16) throw std::runtime_error("Malformed IPv6 address"); - std::ostringstream oss; - oss << std::hex; - for(size_t i = 0; i < 16; i += 2) { - oss << (int)ptr[i] << (int)ptr[i+1]; - if(i != 14) - oss << ':'; - } - addr = oss.str(); + addr = IPv6Address(ptr).to_string(); } else compose_name(ptr, sz, addr); diff --git a/src/ipv6_address.cpp b/src/ipv6_address.cpp index 0da8a54..07347d9 100644 --- a/src/ipv6_address.cpp +++ b/src/ipv6_address.cpp @@ -41,6 +41,10 @@ namespace Tins { std::fill(address, address + address_size, 0); } + IPv6Address::IPv6Address(const_iterator ptr) { + std::copy(ptr, ptr + address_size, address); + } + IPv6Address::IPv6Address(const std::string &addr) { if(inet_pton(AF_INET6, addr.c_str(), address) == 0) throw malformed_address(); diff --git a/tests/src/dns.cpp b/tests/src/dns.cpp index 19b1ca9..2565c39 100644 --- a/tests/src/dns.cpp +++ b/tests/src/dns.cpp @@ -1,6 +1,7 @@ #include #include #include "dns.h" +#include "ipv6_address.h" #include "utils.h" using namespace Tins; @@ -235,3 +236,19 @@ TEST_F(DNSTest, AnswersWithSameName) { EXPECT_EQ(it->query_class(), DNS::IN); } } + +TEST_F(DNSTest, AnswersV6) { + DNS dns; + dns.add_answer("www.example.com", DNS::make_info(DNS::AAAA, DNS::IN, 0x762), IPv6Address("f9a8:239::1:1")); + dns.add_answer("www.example.com", DNS::make_info(DNS::AAAA, DNS::IN, 0x762), IPv6Address("f9a8:239::1:1")); + ASSERT_EQ(dns.answers_count(), 2); + + DNS::resources_type resources = dns.answers(); + for(DNS::resources_type::const_iterator it = resources.begin(); it != resources.end(); ++it) { + EXPECT_EQ(it->dname(), "www.example.com"); + EXPECT_EQ(it->type(), DNS::AAAA); + EXPECT_EQ(it->ttl(), 0x762); + EXPECT_EQ(it->data(), "f9a8:239::1:1"); + EXPECT_EQ(it->query_class(), DNS::IN); + } +}