mirror of
https://github.com/mfontanini/libtins
synced 2026-01-23 02:35:57 +01:00
@@ -221,8 +221,176 @@ public:
|
|||||||
QueryClass qclass_;
|
QueryClass qclass_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Resource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Struct that represent DNS resource records.
|
* \brief Class that represents a Start Of Authority record
|
||||||
|
*/
|
||||||
|
class soa_record {
|
||||||
|
public:
|
||||||
|
|
||||||
|
friend class DNSTest;
|
||||||
|
/**
|
||||||
|
* \brief Default constructor
|
||||||
|
*/
|
||||||
|
soa_record();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Constructs a SOA record from a DNS::resource
|
||||||
|
* \param resource The resource from which to construct this record
|
||||||
|
*/
|
||||||
|
soa_record(const DNS::Resource& resource);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Constructs a SOA record from a buffer
|
||||||
|
* \param buffer The buffer from which to construct this SOA record
|
||||||
|
* \param total_sz The size of the buffer
|
||||||
|
*/
|
||||||
|
soa_record(const uint8_t* buffer, uint32_t total_sz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Constructs a SOA record
|
||||||
|
*
|
||||||
|
* \param mname The primary source name
|
||||||
|
* \param rname The responsible person name
|
||||||
|
* \param serial The serial number
|
||||||
|
* \param refresh The refresh value
|
||||||
|
* \param retry The retry value
|
||||||
|
* \param expire The expire value
|
||||||
|
* \param minimum_ttl The minimum TTL value
|
||||||
|
*/
|
||||||
|
soa_record(const std::string& mname,
|
||||||
|
const std::string& rname,
|
||||||
|
uint32_t serial,
|
||||||
|
uint32_t refresh,
|
||||||
|
uint32_t retry,
|
||||||
|
uint32_t expire,
|
||||||
|
uint32_t minimum_ttl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Getter for the primary source name field
|
||||||
|
*
|
||||||
|
* The returned domain name is already decoded.
|
||||||
|
*
|
||||||
|
* \return mname The primary source name field
|
||||||
|
*/
|
||||||
|
const std::string& mname() const {
|
||||||
|
return mname_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Getter for the responsible person name field
|
||||||
|
*
|
||||||
|
* The returned domain name is already decoded.
|
||||||
|
*
|
||||||
|
* \return mname The responsible person name field
|
||||||
|
*/
|
||||||
|
const std::string& rname() const {
|
||||||
|
return rname_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Getter for the serial number field
|
||||||
|
* \return The serial number field
|
||||||
|
*/
|
||||||
|
uint32_t serial() const {
|
||||||
|
return serial_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Getter for the refresh field
|
||||||
|
* \return The refresh field
|
||||||
|
*/
|
||||||
|
uint32_t refresh() const {
|
||||||
|
return refresh_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Getter for the retry field
|
||||||
|
* \return The retry field
|
||||||
|
*/
|
||||||
|
uint32_t retry() const {
|
||||||
|
return retry_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Getter for the expire field
|
||||||
|
* \return The expire field
|
||||||
|
*/
|
||||||
|
uint32_t expire() const {
|
||||||
|
return expire_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Getter for the minimum TTL field
|
||||||
|
* \return The minimum TTL field
|
||||||
|
*/
|
||||||
|
uint32_t minimum_ttl() const {
|
||||||
|
return minimum_ttl_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Getter for the primary source name field
|
||||||
|
* \param value The new primary source name field value
|
||||||
|
*/
|
||||||
|
void mname(const std::string& value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Getter for the responsible person name field
|
||||||
|
* \param value The new responsible person name field value
|
||||||
|
*/
|
||||||
|
void rname(const std::string& value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Getter for the serial number field
|
||||||
|
* \param value The new serial number field value
|
||||||
|
*/
|
||||||
|
void serial(uint32_t value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Getter for the refresh field
|
||||||
|
* \param value The new refresh field value
|
||||||
|
*/
|
||||||
|
void refresh(uint32_t value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Getter for the retry field
|
||||||
|
* \param value The new retry field value
|
||||||
|
*/
|
||||||
|
void retry(uint32_t value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Getter for the expire field
|
||||||
|
* \param value The new expire field value
|
||||||
|
*/
|
||||||
|
void expire(uint32_t value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Getter for the minimum TTL field
|
||||||
|
* \param value The new minimum TTL field value
|
||||||
|
*/
|
||||||
|
void minimum_ttl(uint32_t value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Serialize this SOA record
|
||||||
|
* \return The serialized SOA record
|
||||||
|
*/
|
||||||
|
PDU::serialization_type serialize() const;
|
||||||
|
private:
|
||||||
|
friend class DNS;
|
||||||
|
void init(const uint8_t* buffer, uint32_t total_sz);
|
||||||
|
|
||||||
|
std::string mname_;
|
||||||
|
std::string rname_;
|
||||||
|
uint32_t serial_;
|
||||||
|
uint32_t refresh_;
|
||||||
|
uint32_t retry_;
|
||||||
|
uint32_t expire_;
|
||||||
|
uint32_t minimum_ttl_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Class that represent DNS resource records.
|
||||||
*/
|
*/
|
||||||
class Resource {
|
class Resource {
|
||||||
public:
|
public:
|
||||||
@@ -317,6 +485,15 @@ public:
|
|||||||
data_ = data;
|
data_ = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Sets the contents of this resource to the provided SOA record
|
||||||
|
* \param data The SOA record that will be stored in this resource
|
||||||
|
*/
|
||||||
|
void data(const soa_record& data) {
|
||||||
|
serialization_type buffer = data.serialize();
|
||||||
|
data_.assign(buffer.begin(), buffer.end());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setter for the type field.
|
* Setter for the type field.
|
||||||
*/
|
*/
|
||||||
@@ -693,6 +870,20 @@ public:
|
|||||||
*/
|
*/
|
||||||
static std::string encode_domain_name(const std::string& domain_name);
|
static std::string encode_domain_name(const std::string& domain_name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Decodes a domain name
|
||||||
|
*
|
||||||
|
* This method processes an encoded domain name and returns the decoded
|
||||||
|
* version. This <b>can't handle</b> offset labels.
|
||||||
|
*
|
||||||
|
* For example, given the input "\x03www\x07example\x03com\x00",
|
||||||
|
* the output would be www.example.com".
|
||||||
|
*
|
||||||
|
* \param domain_name The domain name to decode.
|
||||||
|
* \return The decoded domain name.
|
||||||
|
*/
|
||||||
|
static std::string decode_domain_name(const std::string& domain_name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Check wether ptr points to a valid response for this PDU.
|
* \brief Check wether ptr points to a valid response for this PDU.
|
||||||
*
|
*
|
||||||
@@ -709,6 +900,8 @@ public:
|
|||||||
return new DNS(*this);
|
return new DNS(*this);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
friend class soa_record;
|
||||||
|
|
||||||
TINS_BEGIN_PACK
|
TINS_BEGIN_PACK
|
||||||
struct dns_header {
|
struct dns_header {
|
||||||
uint16_t id;
|
uint16_t id;
|
||||||
|
|||||||
@@ -263,6 +263,16 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Exception thrown when an invalid domain name is parsed
|
||||||
|
*/
|
||||||
|
class invalid_domain_name : public exception_base {
|
||||||
|
public:
|
||||||
|
const char* what() const throw() {
|
||||||
|
return "Invalid domain name";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
namespace Crypto {
|
namespace Crypto {
|
||||||
namespace WPA2 {
|
namespace WPA2 {
|
||||||
/**
|
/**
|
||||||
|
|||||||
152
src/dns.cpp
152
src/dns.cpp
@@ -294,6 +294,39 @@ string DNS::encode_domain_name(const string& dn) {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string DNS::decode_domain_name(const string& domain_name) {
|
||||||
|
string output;
|
||||||
|
if (domain_name.empty()) {
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
const uint8_t* ptr = (const uint8_t*)&domain_name[0];
|
||||||
|
const uint8_t* end = ptr + domain_name.size();
|
||||||
|
while (*ptr) {
|
||||||
|
// We can't handle offsets
|
||||||
|
if ((*ptr & 0xc0)) {
|
||||||
|
throw invalid_domain_name();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// It's a label, grab its size.
|
||||||
|
uint8_t size = *ptr;
|
||||||
|
ptr++;
|
||||||
|
if (ptr + size > end) {
|
||||||
|
throw malformed_packet();
|
||||||
|
}
|
||||||
|
// Append a dot if it's not the first one.
|
||||||
|
if (!output.empty()) {
|
||||||
|
output.push_back('.');
|
||||||
|
}
|
||||||
|
output.insert(output.end(), ptr, ptr + size);
|
||||||
|
ptr += size;
|
||||||
|
}
|
||||||
|
if (output.size() > 256) {
|
||||||
|
throw invalid_domain_name();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
// The output buffer should be at least 256 bytes long. This used to use
|
// 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
|
// a std::string but it worked about 50% slower, so this is somehow
|
||||||
// unsafe but a lot faster.
|
// unsafe but a lot faster.
|
||||||
@@ -380,7 +413,7 @@ void DNS::convert_records(const uint8_t* ptr,
|
|||||||
InputMemoryStream stream(ptr, end - ptr);
|
InputMemoryStream stream(ptr, end - ptr);
|
||||||
char dname[256], small_addr_buf[256];
|
char dname[256], small_addr_buf[256];
|
||||||
while (stream) {
|
while (stream) {
|
||||||
string addr;
|
string data;
|
||||||
bool used_small_buffer = false;
|
bool used_small_buffer = false;
|
||||||
// Retrieve the record's domain name.
|
// Retrieve the record's domain name.
|
||||||
stream.skip(compose_name(stream.pointer(), dname));
|
stream.skip(compose_name(stream.pointer(), dname));
|
||||||
@@ -402,7 +435,7 @@ void DNS::convert_records(const uint8_t* ptr,
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case AAAA:
|
case AAAA:
|
||||||
addr = stream.read<IPv6Address>().to_string();
|
data = stream.read<IPv6Address>().to_string();
|
||||||
break;
|
break;
|
||||||
case A:
|
case A:
|
||||||
inline_convert_v4(stream.read<uint32_t>(), small_addr_buf);
|
inline_convert_v4(stream.read<uint32_t>(), small_addr_buf);
|
||||||
@@ -417,23 +450,29 @@ void DNS::convert_records(const uint8_t* ptr,
|
|||||||
stream.skip(data_size);
|
stream.skip(data_size);
|
||||||
used_small_buffer = true;
|
used_small_buffer = true;
|
||||||
break;
|
break;
|
||||||
|
case SOA:
|
||||||
|
{
|
||||||
|
stream.skip(compose_name(stream.pointer(), small_addr_buf));
|
||||||
|
data = encode_domain_name(small_addr_buf);
|
||||||
|
stream.skip(compose_name(stream.pointer(), small_addr_buf));
|
||||||
|
data += encode_domain_name(small_addr_buf);
|
||||||
|
const uint32_t size_left = sizeof(uint32_t) * 5;
|
||||||
|
if (!stream.can_read(size_left)) {
|
||||||
|
throw malformed_packet();
|
||||||
|
}
|
||||||
|
data.insert(data.end(), stream.pointer(), stream.pointer() + size_left);
|
||||||
|
stream.skip(size_left);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (data_size < sizeof(small_addr_buf) - 1) {
|
data.assign(stream.pointer(), stream.pointer() + data_size);
|
||||||
stream.read(small_addr_buf, data_size);
|
stream.skip(data_size);
|
||||||
// null terminator
|
|
||||||
small_addr_buf[data_size] = 0;
|
|
||||||
used_small_buffer = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
addr.assign(stream.pointer(), stream.pointer() + data_size);
|
|
||||||
stream.skip(data_size);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
res.push_back(
|
res.push_back(
|
||||||
Resource(
|
Resource(
|
||||||
dname,
|
dname,
|
||||||
(used_small_buffer) ? small_addr_buf : addr,
|
(used_small_buffer) ? small_addr_buf : data,
|
||||||
type,
|
type,
|
||||||
qclass,
|
qclass,
|
||||||
ttl,
|
ttl,
|
||||||
@@ -556,4 +595,91 @@ bool DNS::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
|||||||
return hdr->id == header_.id;
|
return hdr->id == header_.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SOA record
|
||||||
|
|
||||||
|
DNS::soa_record::soa_record()
|
||||||
|
: serial_(0), refresh_(0), retry_(0), expire_(0) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
DNS::soa_record::soa_record(const string& mname,
|
||||||
|
const string& rname,
|
||||||
|
uint32_t serial,
|
||||||
|
uint32_t refresh,
|
||||||
|
uint32_t retry,
|
||||||
|
uint32_t expire,
|
||||||
|
uint32_t minimum_ttl)
|
||||||
|
: mname_(mname), rname_(rname), serial_(serial), refresh_(refresh), retry_(retry),
|
||||||
|
expire_(expire), minimum_ttl_(minimum_ttl) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
DNS::soa_record::soa_record(const uint8_t* buffer, uint32_t total_sz) {
|
||||||
|
init(buffer, total_sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
DNS::soa_record::soa_record(const DNS::Resource& resource) {
|
||||||
|
init((const uint8_t*)&resource.data()[0], resource.data().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DNS::soa_record::mname(const string& value) {
|
||||||
|
mname_ = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DNS::soa_record::rname(const string& value) {
|
||||||
|
rname_ = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DNS::soa_record::serial(uint32_t value) {
|
||||||
|
serial_ = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DNS::soa_record::refresh(uint32_t value) {
|
||||||
|
refresh_ = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DNS::soa_record::retry(uint32_t value) {
|
||||||
|
retry_ = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DNS::soa_record::expire(uint32_t value) {
|
||||||
|
expire_ = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DNS::soa_record::minimum_ttl(uint32_t value) {
|
||||||
|
minimum_ttl_ = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDU::serialization_type DNS::soa_record::serialize() const {
|
||||||
|
string encoded_mname = DNS::encode_domain_name(mname_);
|
||||||
|
string encoded_rname = DNS::encode_domain_name(rname_);
|
||||||
|
PDU::serialization_type output(
|
||||||
|
encoded_mname.size() + encoded_rname.size() + sizeof(uint32_t) * 5
|
||||||
|
);
|
||||||
|
OutputMemoryStream stream(output);
|
||||||
|
stream.write(encoded_mname.begin(), encoded_mname.end());
|
||||||
|
stream.write(encoded_rname.begin(), encoded_rname.end());
|
||||||
|
stream.write_be(serial_);
|
||||||
|
stream.write_be(refresh_);
|
||||||
|
stream.write_be(retry_);
|
||||||
|
stream.write_be(expire_);
|
||||||
|
stream.write_be(minimum_ttl_);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DNS::soa_record::init(const uint8_t* buffer, uint32_t total_sz) {
|
||||||
|
InputMemoryStream stream(buffer, total_sz);
|
||||||
|
string domain = (const char*)stream.pointer();
|
||||||
|
mname_ = DNS::decode_domain_name(domain);
|
||||||
|
stream.skip(domain.size() + 1);
|
||||||
|
domain = (const char*)stream.pointer();
|
||||||
|
stream.skip(domain.size() + 1);
|
||||||
|
rname_ = DNS::decode_domain_name(domain);
|
||||||
|
serial_ = stream.read_be<uint32_t>();
|
||||||
|
refresh_ = stream.read_be<uint32_t>();
|
||||||
|
retry_ = stream.read_be<uint32_t>();
|
||||||
|
expire_ = stream.read_be<uint32_t>();
|
||||||
|
minimum_ttl_ = stream.read_be<uint32_t>();
|
||||||
|
}
|
||||||
|
|
||||||
} // Tins
|
} // Tins
|
||||||
|
|||||||
@@ -473,3 +473,83 @@ TEST_F(DNSTest, MXPreferenceField) {
|
|||||||
EXPECT_EQ(42, resource.preference());
|
EXPECT_EQ(42, resource.preference());
|
||||||
EXPECT_EQ("example.com", resource.dname());
|
EXPECT_EQ("example.com", resource.dname());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DNSTest, SOARecordConstructor) {
|
||||||
|
DNS::soa_record r(
|
||||||
|
"hehehehe.example.com",
|
||||||
|
"john.example.com",
|
||||||
|
0x9823ade9,
|
||||||
|
0x918273aa,
|
||||||
|
0x827361ad,
|
||||||
|
0x8ad71928,
|
||||||
|
0x1ad92871
|
||||||
|
);
|
||||||
|
EXPECT_EQ("hehehehe.example.com", r.mname());
|
||||||
|
EXPECT_EQ("john.example.com", r.rname());
|
||||||
|
EXPECT_EQ(0x9823ade9, r.serial());
|
||||||
|
EXPECT_EQ(0x918273aa, r.refresh());
|
||||||
|
EXPECT_EQ(0x827361ad, r.retry());
|
||||||
|
EXPECT_EQ(0x8ad71928, r.expire());
|
||||||
|
EXPECT_EQ(0x1ad92871, r.minimum_ttl());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DNSTest, SOARecordGettersAndSetters) {
|
||||||
|
DNS::soa_record r;
|
||||||
|
r.mname("hehehehe.example.com");
|
||||||
|
r.rname("john.example.com");
|
||||||
|
r.serial(0x9823ade9);
|
||||||
|
r.refresh(0x918273aa);
|
||||||
|
r.retry(0x827361ad);
|
||||||
|
r.expire(0x8ad71928);
|
||||||
|
r.minimum_ttl(0x1ad92871);
|
||||||
|
EXPECT_EQ("hehehehe.example.com", r.mname());
|
||||||
|
EXPECT_EQ("john.example.com", r.rname());
|
||||||
|
EXPECT_EQ(0x9823ade9, r.serial());
|
||||||
|
EXPECT_EQ(0x918273aa, r.refresh());
|
||||||
|
EXPECT_EQ(0x827361ad, r.retry());
|
||||||
|
EXPECT_EQ(0x8ad71928, r.expire());
|
||||||
|
EXPECT_EQ(0x1ad92871, r.minimum_ttl());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DNSTest, SOARecordFromBuffer) {
|
||||||
|
const uint8_t raw[] = {
|
||||||
|
232, 101, 129, 128, 0, 1, 0, 1, 0, 0, 0, 0, 6, 103, 111, 111, 103, 108,
|
||||||
|
101, 3, 99, 111, 109, 0, 0, 6, 0, 1, 192, 12, 0, 6, 0, 1, 0, 0, 0, 59,
|
||||||
|
0, 38, 3, 110, 115, 50, 192, 12, 9, 100, 110, 115, 45, 97, 100, 109, 105,
|
||||||
|
110, 192, 12, 6, 174, 163, 84, 0, 0, 3, 132, 0, 0, 3, 132, 0, 0, 7, 8, 0,
|
||||||
|
0, 0, 60
|
||||||
|
};
|
||||||
|
|
||||||
|
DNS dns(raw, sizeof(raw));
|
||||||
|
ASSERT_EQ(1, dns.answers().size());
|
||||||
|
DNS::Resource r(dns.answers().front());
|
||||||
|
DNS::soa_record soa(r);
|
||||||
|
EXPECT_EQ("ns2.google.com", soa.mname());
|
||||||
|
EXPECT_EQ("dns-admin.google.com", soa.rname());
|
||||||
|
EXPECT_EQ(112108372, soa.serial());
|
||||||
|
EXPECT_EQ(900, soa.refresh());
|
||||||
|
EXPECT_EQ(900, soa.retry());
|
||||||
|
EXPECT_EQ(1800, soa.expire());
|
||||||
|
EXPECT_EQ(60, soa.minimum_ttl());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DNSTest, SOARecordSerialize) {
|
||||||
|
DNS::soa_record r1;
|
||||||
|
r1.mname("hehehehe.example.com");
|
||||||
|
r1.rname("john.example.com");
|
||||||
|
r1.serial(0x9823ade9);
|
||||||
|
r1.refresh(0x918273aa);
|
||||||
|
r1.retry(0x827361ad);
|
||||||
|
r1.expire(0x8ad71928);
|
||||||
|
r1.minimum_ttl(0x1ad92871);
|
||||||
|
|
||||||
|
DNS::serialization_type buffer = r1.serialize();
|
||||||
|
DNS::soa_record r2(&buffer[0], buffer.size());
|
||||||
|
EXPECT_EQ("hehehehe.example.com", r2.mname());
|
||||||
|
EXPECT_EQ("john.example.com", r2.rname());
|
||||||
|
EXPECT_EQ(0x9823ade9, r2.serial());
|
||||||
|
EXPECT_EQ(0x918273aa, r2.refresh());
|
||||||
|
EXPECT_EQ(0x827361ad, r2.retry());
|
||||||
|
EXPECT_EQ(0x8ad71928, r2.expire());
|
||||||
|
EXPECT_EQ(0x1ad92871, r2.minimum_ttl());
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user