Add MulticastDnsClient
This commit is contained in:
@@ -0,0 +1,129 @@
|
|||||||
|
#include "Data.h"
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
Data::Data()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Data::Data(const std::vector<uint8_t>& data) :
|
||||||
|
m_data(data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Data::Data(const uint8_t* msg, unsigned length) :
|
||||||
|
m_data(msg, msg + length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Data::Data(const Data& data) :
|
||||||
|
m_data(data.m_data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t& Data::GetAt(unsigned pos)
|
||||||
|
{
|
||||||
|
return m_data[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t& Data::GetAt(unsigned pos) const
|
||||||
|
{
|
||||||
|
return m_data[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t& Data::GetAt16(unsigned pos)
|
||||||
|
{
|
||||||
|
return *((uint16_t*)(GetPtr() + pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint16_t& Data::GetAt16(unsigned pos) const
|
||||||
|
{
|
||||||
|
return *((const uint16_t*)(GetPtr() + pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t& Data::GetAt32(unsigned pos)
|
||||||
|
{
|
||||||
|
return *((uint32_t*)(GetPtr() + pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t& Data::GetAt32(unsigned pos) const
|
||||||
|
{
|
||||||
|
return *((const uint32_t*)(GetPtr() + pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* Data::GetPtr() const
|
||||||
|
{
|
||||||
|
return m_data.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Data::GetLength() const
|
||||||
|
{
|
||||||
|
return static_cast<unsigned>(m_data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Data::append(const Data& data)
|
||||||
|
{
|
||||||
|
m_data.insert(m_data.end(), data.m_data.begin(), data.m_data.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Data::append(uint8_t value)
|
||||||
|
{
|
||||||
|
m_data.emplace_back(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Data::append(uint16_t value)
|
||||||
|
{
|
||||||
|
m_data.emplace_back(static_cast<uint8_t>((value >> 8) & ((1 << 8) - 1)));
|
||||||
|
m_data.emplace_back(static_cast<uint8_t>((value >> 0) & ((1 << 8) - 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Data::append(uint32_t value)
|
||||||
|
{
|
||||||
|
m_data.emplace_back(static_cast<uint8_t>((value >> 24) & ((1 << 8) - 1)));
|
||||||
|
m_data.emplace_back(static_cast<uint8_t>((value >> 16) & ((1 << 8) - 1)));
|
||||||
|
m_data.emplace_back(static_cast<uint8_t>((value >> 8) & ((1 << 8) - 1)));
|
||||||
|
m_data.emplace_back(static_cast<uint8_t>((value >> 0) & ((1 << 8) - 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Data::append(uint64_t value)
|
||||||
|
{
|
||||||
|
m_data.emplace_back(static_cast<uint8_t>((value >> 56) & ((1 << 8) - 1)));
|
||||||
|
m_data.emplace_back(static_cast<uint8_t>((value >> 48) & ((1 << 8) - 1)));
|
||||||
|
m_data.emplace_back(static_cast<uint8_t>((value >> 40) & ((1 << 8) - 1)));
|
||||||
|
m_data.emplace_back(static_cast<uint8_t>((value >> 32) & ((1 << 8) - 1)));
|
||||||
|
m_data.emplace_back(static_cast<uint8_t>((value >> 24) & ((1 << 8) - 1)));
|
||||||
|
m_data.emplace_back(static_cast<uint8_t>((value >> 16) & ((1 << 8) - 1)));
|
||||||
|
m_data.emplace_back(static_cast<uint8_t>((value >> 8) & ((1 << 8) - 1)));
|
||||||
|
m_data.emplace_back(static_cast<uint8_t>((value >> 0) & ((1 << 8) - 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Data::prepend(const Data& data)
|
||||||
|
{
|
||||||
|
m_data.insert(m_data.begin(), data.m_data.begin(), data.m_data.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Data::swap(Data& x) noexcept
|
||||||
|
{
|
||||||
|
m_data.swap(x.m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& stream, const Data& data)
|
||||||
|
{
|
||||||
|
const uint8_t* ptr = data.GetPtr();
|
||||||
|
int length = data.GetLength();
|
||||||
|
stream << "Data[" << length << "](";
|
||||||
|
for (int i = 0; i < length; ++i)
|
||||||
|
{
|
||||||
|
if (i)
|
||||||
|
stream << ", ";
|
||||||
|
stream << static_cast<int>(ptr[i]);
|
||||||
|
}
|
||||||
|
stream << ")";
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#ifndef NETWORK_DNS_DATA_H
|
||||||
|
#define NETWORK_DNS_DATA_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class Data
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Data();
|
||||||
|
Data(const std::vector<uint8_t>& data);
|
||||||
|
Data(const uint8_t* msg, unsigned length);
|
||||||
|
Data(const Data& data);
|
||||||
|
|
||||||
|
uint8_t& GetAt(unsigned pos);
|
||||||
|
const uint8_t& GetAt(unsigned pos) const;
|
||||||
|
uint16_t& GetAt16(unsigned pos);
|
||||||
|
const uint16_t& GetAt16(unsigned pos) const;
|
||||||
|
uint32_t& GetAt32(unsigned pos);
|
||||||
|
const uint32_t& GetAt32(unsigned pos) const;
|
||||||
|
|
||||||
|
const uint8_t* GetPtr() const;
|
||||||
|
unsigned GetLength() const;
|
||||||
|
|
||||||
|
void append(const Data& data);
|
||||||
|
void append(uint8_t value);
|
||||||
|
void append(uint16_t value);
|
||||||
|
void append(uint32_t value);
|
||||||
|
void append(uint64_t value);
|
||||||
|
|
||||||
|
template<typename Arg1, typename ...Args>
|
||||||
|
void append(Arg1 value, Args ...args)
|
||||||
|
{
|
||||||
|
append(value);
|
||||||
|
append(args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepend(const Data& data);
|
||||||
|
|
||||||
|
void swap(Data& x) noexcept;
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream& stream, const Data& data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<uint8_t> m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // NETWORK_DNS_DATA_H
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
#include "DataReader.h"
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
DataReader::DataReader(const uint8_t* data, unsigned length) :
|
||||||
|
m_data(data),
|
||||||
|
m_length(length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DataReader::DataReader(const std::vector<uint8_t>& data) :
|
||||||
|
DataReader(data.data(), data.size())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* DataReader::GetPtr() const
|
||||||
|
{
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned DataReader::GetLength() const
|
||||||
|
{
|
||||||
|
return m_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t DataReader::operator[](unsigned index) const
|
||||||
|
{
|
||||||
|
if (index >= m_length)
|
||||||
|
throw DataReaderOutOfBounds();
|
||||||
|
return m_data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
DataReader& DataReader::operator+=(unsigned index)
|
||||||
|
{
|
||||||
|
if (index > m_length)
|
||||||
|
throw DataReaderOutOfBounds();
|
||||||
|
m_data += index;
|
||||||
|
m_length -= index;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DataReader DataReader::operator+(unsigned index) const
|
||||||
|
{
|
||||||
|
DataReader reader(*this);
|
||||||
|
return reader += index;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t DataReader::Read8(unsigned& pos) const
|
||||||
|
{
|
||||||
|
uint8_t value =
|
||||||
|
(static_cast<uint8_t>((*this)[pos + 0]) << 0);
|
||||||
|
pos++;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t DataReader::Read16(unsigned& pos) const
|
||||||
|
{
|
||||||
|
uint16_t value =
|
||||||
|
(static_cast<uint16_t>((*this)[pos + 0]) << 8) |
|
||||||
|
(static_cast<uint16_t>((*this)[pos + 1]) << 0);
|
||||||
|
pos += 2;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DataReader::Read32(unsigned& pos) const
|
||||||
|
{
|
||||||
|
uint32_t value =
|
||||||
|
(static_cast<uint32_t>((*this)[pos + 0]) << 24) |
|
||||||
|
(static_cast<uint32_t>((*this)[pos + 1]) << 16) |
|
||||||
|
(static_cast<uint32_t>((*this)[pos + 2]) << 8) |
|
||||||
|
(static_cast<uint32_t>((*this)[pos + 3]) << 0);
|
||||||
|
pos += 4;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t DataReader::Read64(unsigned& pos) const
|
||||||
|
{
|
||||||
|
uint64_t value =
|
||||||
|
(static_cast<uint64_t>((*this)[pos + 0]) << 56) |
|
||||||
|
(static_cast<uint64_t>((*this)[pos + 1]) << 48) |
|
||||||
|
(static_cast<uint64_t>((*this)[pos + 2]) << 40) |
|
||||||
|
(static_cast<uint64_t>((*this)[pos + 3]) << 32) |
|
||||||
|
(static_cast<uint64_t>((*this)[pos + 4]) << 24) |
|
||||||
|
(static_cast<uint64_t>((*this)[pos + 5]) << 16) |
|
||||||
|
(static_cast<uint64_t>((*this)[pos + 6]) << 8) |
|
||||||
|
(static_cast<uint64_t>((*this)[pos + 7]) << 0);
|
||||||
|
pos += 8;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& stream, const DataReader& reader)
|
||||||
|
{
|
||||||
|
stream << "DataReader[" << reader.m_length << "] = {";
|
||||||
|
for (unsigned i = 0; i < reader.m_length; ++i)
|
||||||
|
{
|
||||||
|
if (i)
|
||||||
|
stream << ", ";
|
||||||
|
for(int j = 7; j >= 0; j--)
|
||||||
|
if (reader.m_data[i] & (1 << j))
|
||||||
|
stream << "1";
|
||||||
|
else
|
||||||
|
stream << "0";
|
||||||
|
stream << " " << static_cast<int>(reader.m_data[i]);
|
||||||
|
}
|
||||||
|
stream << "}";
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#ifndef NETWORK_DNS_DATAREADER_H
|
||||||
|
#define NETWORK_DNS_DATAREADER_H
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class DataReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DataReader(const uint8_t* data, unsigned length);
|
||||||
|
DataReader(const std::vector<uint8_t>& data);
|
||||||
|
|
||||||
|
const uint8_t* GetPtr() const;
|
||||||
|
unsigned GetLength() const;
|
||||||
|
|
||||||
|
uint8_t operator[](unsigned index) const;
|
||||||
|
|
||||||
|
DataReader& operator+=(unsigned index);
|
||||||
|
const DataReader operator+(unsigned index) const;
|
||||||
|
|
||||||
|
uint8_t Read8(unsigned& pos) const;
|
||||||
|
uint16_t Read16(unsigned& pos) const;
|
||||||
|
uint32_t Read32(unsigned& pos) const;
|
||||||
|
uint64_t Read64(unsigned& pos) const;
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream& strem, const DataReader& reader);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uint8_t* m_data;
|
||||||
|
unsigned m_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DataReaderOutOfBounds : public std::exception
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // NETWORK_DNS_DATAREADER_H
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../Makefile
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef NETWORK_DNS_MALFORMEDPACKET_H
|
||||||
|
#define NETWORK_DNS_MALFORMEDPACKET_H
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class MalformedPacket : public std::exception
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // NETWORK_DNS_MALFORMEDPACKET_H
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#include "Dns/MulticastDnsClient.h"
|
||||||
|
#include "MulticastDnsClientImpl.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
MulticastDnsClient::MulticastDnsClient(std::function<void(const std::vector<ResourceRecord>&)> callback) :
|
||||||
|
m_pMulticastDnsClientImpl(new MulticastDnsClientImpl(std::bind(&MulticastDnsClient::Callback, this, std::placeholders::_1))),
|
||||||
|
m_callback(callback)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MulticastDnsClient::~MulticastDnsClient() = default;
|
||||||
|
|
||||||
|
void MulticastDnsClient::Query(const Dns::Query& query)
|
||||||
|
{
|
||||||
|
m_pMulticastDnsClientImpl->Query(*query.PImpl());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MulticastDnsClient::Callback(const std::vector<ResourceRecordImpl>& answers)
|
||||||
|
{
|
||||||
|
std::vector<ResourceRecord> ans;
|
||||||
|
|
||||||
|
for (auto& answer : answers)
|
||||||
|
ans.push_back(ResourceRecord(std::make_shared<ResourceRecordImpl>(answer)));
|
||||||
|
|
||||||
|
m_callback(ans);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
#include "MulticastDnsClientImpl.h"
|
||||||
|
#include "MalformedPacket.h"
|
||||||
|
#include "Packet.h"
|
||||||
|
#include <Logging.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
MulticastDnsClientImpl::MulticastDnsClientImpl(std::function<void(const std::vector<ResourceRecordImpl>&)> callback) :
|
||||||
|
m_timer(m_ioService),
|
||||||
|
m_responseBuffer(1024),
|
||||||
|
m_socket(m_ioService, asio::ip::udp::v4()),
|
||||||
|
m_multicastEndpoint(asio::ip::address::from_string("224.0.0.251"), 5353),
|
||||||
|
m_callback(callback)
|
||||||
|
{
|
||||||
|
m_socket.set_option(asio::socket_base::reuse_address(true));
|
||||||
|
m_socket.set_option(asio::ip::multicast::join_group(m_multicastEndpoint.address()));
|
||||||
|
m_socket.set_option(asio::ip::multicast::hops(255));
|
||||||
|
m_socket.bind(asio::ip::udp::endpoint(asio::ip::udp::v4(), 5353));
|
||||||
|
|
||||||
|
m_thread = std::thread([&] { m_ioService.run(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
MulticastDnsClientImpl::~MulticastDnsClientImpl()
|
||||||
|
{
|
||||||
|
m_ioService.stop();
|
||||||
|
m_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MulticastDnsClientImpl::Query(const QueryImpl& query)
|
||||||
|
{
|
||||||
|
m_query = query;
|
||||||
|
m_iterations = 3;
|
||||||
|
SendQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MulticastDnsClientImpl::SetTimer(int milliseconds)
|
||||||
|
{
|
||||||
|
m_timer.cancel();
|
||||||
|
m_timer.expires_from_now(std::chrono::milliseconds(milliseconds));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MulticastDnsClientImpl::SendQuery()
|
||||||
|
{
|
||||||
|
if (m_iterations == 0)
|
||||||
|
return;
|
||||||
|
m_iterations--;
|
||||||
|
|
||||||
|
Packet packet;
|
||||||
|
packet.AddQuery(m_query);
|
||||||
|
|
||||||
|
auto data = std::make_shared<Data>(packet.GetData());
|
||||||
|
|
||||||
|
m_socket.async_send_to(
|
||||||
|
asio::buffer(data->GetPtr(), data->GetLength()),
|
||||||
|
m_multicastEndpoint,
|
||||||
|
std::bind(&MulticastDnsClientImpl::HandleQuerySent, this,
|
||||||
|
std::placeholders::_1,
|
||||||
|
data
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MulticastDnsClientImpl::HandleQuerySent(const asio::error_code & error, std::shared_ptr<Data> data)
|
||||||
|
{
|
||||||
|
if (error == asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
SendQuery();
|
||||||
|
}
|
||||||
|
else if (error)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "MulticastDnsClientImpl::HandleQuerySent: " << error.message();
|
||||||
|
Logging::Log(Logging::Severity::Error, ss.str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetTimer(1000);
|
||||||
|
m_timer.async_wait(std::bind(
|
||||||
|
&MulticastDnsClientImpl::HandleQueryTimeout, this,
|
||||||
|
std::placeholders::_1
|
||||||
|
));
|
||||||
|
ReceiveQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MulticastDnsClientImpl::ReceiveQuery()
|
||||||
|
{
|
||||||
|
m_socket.async_receive_from(
|
||||||
|
asio::buffer(m_responseBuffer),
|
||||||
|
m_receiveEndpoint,
|
||||||
|
std::bind(&MulticastDnsClientImpl::HandleQueryResponse, this,
|
||||||
|
std::placeholders::_1,
|
||||||
|
std::placeholders::_2
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MulticastDnsClientImpl::HandleQueryResponse(const asio::error_code & error, std::size_t size)
|
||||||
|
{
|
||||||
|
if (error == asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
SendQuery();
|
||||||
|
}
|
||||||
|
else if (error)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "MulticastDnsClientImpl::HandleQueryResponse: " << error.message();
|
||||||
|
Logging::Log(Logging::Severity::Error, ss.str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Packet packet(DataReader(m_responseBuffer.data(), size), 0);
|
||||||
|
if (packet.GetQuery())
|
||||||
|
m_callback(packet.GetAnswers());
|
||||||
|
}
|
||||||
|
catch(MalformedPacket& mp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ReceiveQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MulticastDnsClientImpl::HandleQueryTimeout(const asio::error_code & error)
|
||||||
|
{
|
||||||
|
if (error == asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (error)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "MulticastDnsClientImpl::HandleQueryTimeout: " << error.message();
|
||||||
|
Logging::Log(Logging::Severity::Error, ss.str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_socket.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#ifndef NETWORK_DNS_MULTICASTDNSCLIENTIMPL_H
|
||||||
|
#define NETWORK_DNS_MULTICASTDNSCLIENTIMPL_H
|
||||||
|
|
||||||
|
#include "QueryImpl.h"
|
||||||
|
#include "ResourceRecordImpl.h"
|
||||||
|
#include <asio.hpp>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class MulticastDnsClientImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MulticastDnsClientImpl(std::function<void(const std::vector<ResourceRecordImpl>&)> callback);
|
||||||
|
~MulticastDnsClientImpl();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void Query(const QueryImpl& query);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetTimer(int milliseconds);
|
||||||
|
void SendQuery();
|
||||||
|
void HandleQuerySent(const asio::error_code & error, std::shared_ptr<Data> data);
|
||||||
|
void ReceiveQuery();
|
||||||
|
void HandleQueryResponse(const asio::error_code & error, std::size_t size);
|
||||||
|
void HandleQueryTimeout(const asio::error_code & error);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::thread m_thread;
|
||||||
|
asio::io_service m_ioService;
|
||||||
|
asio::system_timer m_timer;
|
||||||
|
|
||||||
|
std::vector<uint8_t> m_responseBuffer;
|
||||||
|
|
||||||
|
asio::ip::udp::socket m_socket;
|
||||||
|
asio::ip::udp::endpoint m_multicastEndpoint;
|
||||||
|
asio::ip::udp::endpoint m_receiveEndpoint;
|
||||||
|
|
||||||
|
int m_iterations;
|
||||||
|
QueryImpl m_query;
|
||||||
|
std::function<void(const std::vector<ResourceRecordImpl>&)> m_callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // NETWORK_DNS_MULTICASTDNSCLIENTIMPL_H
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
#include "Dns/Name.h"
|
||||||
|
#include "NameImpl.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
Name::Name() :
|
||||||
|
m_pNameImpl(new NameImpl())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Name::Name(std::shared_ptr<NameImpl> pNameImpl) :
|
||||||
|
m_pNameImpl(pNameImpl)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Name::Name(const std::vector<std::string>& labels) :
|
||||||
|
m_pNameImpl(new NameImpl(labels))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Name::GetFirstLabel() const
|
||||||
|
{
|
||||||
|
return m_pNameImpl->GetFirstLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Name::GetName() const
|
||||||
|
{
|
||||||
|
return m_pNameImpl->GetName();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Name::empty() const
|
||||||
|
{
|
||||||
|
return m_pNameImpl->empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Name::endsWith(const Name& suffix) const
|
||||||
|
{
|
||||||
|
return m_pNameImpl->endsWith(*suffix.PImpl());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Name::append(const std::string& label)
|
||||||
|
{
|
||||||
|
m_pNameImpl->append(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Name::prepend(const std::string& label)
|
||||||
|
{
|
||||||
|
m_pNameImpl->prepend(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Name::swap(Name& x) noexcept
|
||||||
|
{
|
||||||
|
m_pNameImpl->swap(*x.PImpl());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Name::operator==(const Name& name) const
|
||||||
|
{
|
||||||
|
return m_pNameImpl->operator==(*name.PImpl());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Name::operator!=(const Name& name) const
|
||||||
|
{
|
||||||
|
return m_pNameImpl->operator!=(*name.PImpl());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Name::operator<(const Name& name) const
|
||||||
|
{
|
||||||
|
return m_pNameImpl->operator<(*name.PImpl());
|
||||||
|
}
|
||||||
|
|
||||||
|
NameImpl* Name::PImpl() const
|
||||||
|
{
|
||||||
|
return m_pNameImpl.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
#include "NameImpl.h"
|
||||||
|
#include "MalformedPacket.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
NameImpl::NameImpl()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NameImpl::NameImpl(const std::vector<std::string>& labels) :
|
||||||
|
m_labels(labels)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NameImpl::GetFirstLabel() const
|
||||||
|
{
|
||||||
|
if (m_labels.empty())
|
||||||
|
return std::string();
|
||||||
|
return m_labels[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NameImpl::GetName() const
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
for (const std::string& s : m_labels)
|
||||||
|
{
|
||||||
|
if(name != "")
|
||||||
|
name += '.';
|
||||||
|
name += s;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NameImpl::empty() const
|
||||||
|
{
|
||||||
|
return m_labels.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NameImpl::endsWith(const NameImpl& name) const
|
||||||
|
{
|
||||||
|
unsigned size_l = m_labels.size();
|
||||||
|
unsigned name_size_l = name.m_labels.size();
|
||||||
|
if (name_size_l > size_l)
|
||||||
|
return false;
|
||||||
|
for (size_t i = 0; i < name_size_l; i++)
|
||||||
|
if (m_labels[size_l - 1 - i] != name.m_labels[name_size_l - 1 - i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data NameImpl::GetData() const
|
||||||
|
{
|
||||||
|
Data data;
|
||||||
|
for (const std::string& s : m_labels)
|
||||||
|
{
|
||||||
|
data.append(static_cast<uint8_t>(s.length()));
|
||||||
|
for (char c : s)
|
||||||
|
data.append((uint8_t) c);
|
||||||
|
}
|
||||||
|
data.append((uint8_t) 0);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NameImpl::append(const std::string& label)
|
||||||
|
{
|
||||||
|
m_labels.push_back(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NameImpl::prepend(const std::string& label)
|
||||||
|
{
|
||||||
|
m_labels.insert(m_labels.begin(), label);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned NameImpl::ReadFromData(DataReader reader, unsigned pos)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::vector<std::string> newLabels;
|
||||||
|
const uint8_t twoHighBits = 3 << 6; // = 11000000
|
||||||
|
unsigned maxPos = pos;
|
||||||
|
unsigned start = pos;
|
||||||
|
while (reader[pos] != 0)
|
||||||
|
{
|
||||||
|
if ((reader[pos] & twoHighBits) == twoHighBits)
|
||||||
|
{
|
||||||
|
unsigned newPos = ((static_cast<unsigned>(reader[pos] ^ twoHighBits)) << 8) | reader[pos + 1];
|
||||||
|
if(newPos >= start)
|
||||||
|
throw MalformedPacket();
|
||||||
|
maxPos = std::max(maxPos, pos + 2);
|
||||||
|
start = pos = newPos;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned length = reader[pos];
|
||||||
|
std::string label;
|
||||||
|
for (unsigned i = 1; i <= length; i++)
|
||||||
|
label += static_cast<char>(reader[pos + i]);
|
||||||
|
pos += length + 1;
|
||||||
|
newLabels.emplace_back(label);
|
||||||
|
maxPos = std::max(maxPos, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_labels.swap(newLabels);
|
||||||
|
return std::max(maxPos, pos + 1);
|
||||||
|
}
|
||||||
|
catch(const DataReaderOutOfBounds& droob)
|
||||||
|
{
|
||||||
|
throw MalformedPacket();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NameImpl::swap(NameImpl& x) noexcept
|
||||||
|
{
|
||||||
|
std::swap(m_labels, x.m_labels);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NameImpl::operator==(const NameImpl& name) const
|
||||||
|
{
|
||||||
|
return m_labels == name.m_labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NameImpl::operator!=(const NameImpl& name) const
|
||||||
|
{
|
||||||
|
return !(*this == name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NameImpl::operator<(const NameImpl& name) const
|
||||||
|
{
|
||||||
|
return m_labels < name.m_labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& stream, const NameImpl& name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < static_cast<int>(name.m_labels.size()); ++i)
|
||||||
|
{
|
||||||
|
if (i)
|
||||||
|
stream << ".";
|
||||||
|
stream << "\"" << name.m_labels[i] << "\"";
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#ifndef NETWORK_DNS_NAMEIMPL_H
|
||||||
|
#define NETWORK_DNS_NAMEIMPL_H
|
||||||
|
|
||||||
|
#include "Data.h"
|
||||||
|
#include "DataReader.h"
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class NameImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NameImpl();
|
||||||
|
|
||||||
|
template<typename ...Args>
|
||||||
|
NameImpl(const std::string& label, const Args& ...args) : NameImpl(args...)
|
||||||
|
{
|
||||||
|
m_labels.insert(m_labels.begin(), label);
|
||||||
|
}
|
||||||
|
|
||||||
|
NameImpl(const std::vector<std::string>& labels);
|
||||||
|
|
||||||
|
std::string GetFirstLabel() const;
|
||||||
|
std::string GetName() const;
|
||||||
|
bool empty() const;
|
||||||
|
bool endsWith(const NameImpl& suffix) const;
|
||||||
|
Data GetData() const;
|
||||||
|
|
||||||
|
void append(const std::string& label);
|
||||||
|
void prepend(const std::string& label);
|
||||||
|
|
||||||
|
unsigned ReadFromData(DataReader reader, unsigned pos);
|
||||||
|
|
||||||
|
void swap(NameImpl& x) noexcept;
|
||||||
|
|
||||||
|
bool operator==(const NameImpl& name) const;
|
||||||
|
bool operator!=(const NameImpl& name) const;
|
||||||
|
bool operator<(const NameImpl& name) const;
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream& stream, const NameImpl& name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::string> m_labels;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // NETWORK_DNS_NAMEIMPL_H
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef NETWORK_DNS_OPERATIONCODE_H
|
||||||
|
#define NETWORK_DNS_OPERATIONCODE_H
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class OperationCode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum type
|
||||||
|
{
|
||||||
|
QUERY = 0,
|
||||||
|
IQUERY = 1,
|
||||||
|
STATUS = 2
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // NETWORK_DNS_OPERATIONCODE_H
|
||||||
@@ -0,0 +1,284 @@
|
|||||||
|
#include "Packet.h"
|
||||||
|
#include "MalformedPacket.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
Packet::Packet() :
|
||||||
|
m_identifier(0),
|
||||||
|
m_query(0),
|
||||||
|
m_authorativeAnswer(0),
|
||||||
|
m_truncation(0),
|
||||||
|
m_recursionDesired(0),
|
||||||
|
m_recursionAvailable(0),
|
||||||
|
m_zero(0),
|
||||||
|
m_operationCode(OperationCode::QUERY),
|
||||||
|
m_responseCode(ResponseCode::NO_ERROR)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet::Packet(DataReader reader, unsigned pos)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_identifier = reader.Read16(pos);
|
||||||
|
|
||||||
|
uint8_t flags = reader.Read8(pos);
|
||||||
|
m_query = (flags & (1 << 7)) >> 7; // 10000000
|
||||||
|
m_operationCode = static_cast<OperationCode::type>(((flags & (((1 << 4) - 1) << 3)) >> 3)); // 01111000
|
||||||
|
m_authorativeAnswer = (flags & (1 << 2)) >> 2; // 00000100
|
||||||
|
m_truncation = (flags & (1 << 1)) >> 1; // 00000010
|
||||||
|
m_recursionDesired = (flags & (1 << 0)) >> 0; // 00000001
|
||||||
|
|
||||||
|
flags = reader.Read8(pos);
|
||||||
|
m_recursionAvailable = (flags & (1 << 7)) >> 7; // 10000000
|
||||||
|
m_zero = (flags & (((1 << 3) - 1) << 4)) >> 4; // 01110000
|
||||||
|
m_responseCode = static_cast<ResponseCode::type>((flags & ((1 << 4) - 1))); // 00001111
|
||||||
|
|
||||||
|
unsigned queryCount = reader.Read16(pos);
|
||||||
|
unsigned answerCount = reader.Read16(pos);
|
||||||
|
unsigned authorityCount = reader.Read16(pos);
|
||||||
|
unsigned additionalRecordsCount = reader.Read16(pos);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < queryCount; i++)
|
||||||
|
{
|
||||||
|
m_queries.emplace_back();
|
||||||
|
pos = m_queries.back().ReadFromData(reader, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < answerCount; i++)
|
||||||
|
{
|
||||||
|
m_answers.emplace_back();
|
||||||
|
pos = m_answers.back().ReadFromData(reader, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < authorityCount; i++)
|
||||||
|
{
|
||||||
|
m_authorities.emplace_back();
|
||||||
|
pos = m_authorities.back().ReadFromData(reader, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < additionalRecordsCount; i++)
|
||||||
|
{
|
||||||
|
m_additionalRecords.emplace_back();
|
||||||
|
pos = m_additionalRecords.back().ReadFromData(reader, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const DataReaderOutOfBounds& droob)
|
||||||
|
{
|
||||||
|
throw MalformedPacket();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Data Packet::GetData() const
|
||||||
|
{
|
||||||
|
Data data;
|
||||||
|
data.append(static_cast<uint16_t>(m_identifier));
|
||||||
|
|
||||||
|
uint8_t flags =
|
||||||
|
(static_cast<uint8_t>(m_query) << 7) |
|
||||||
|
(static_cast<uint8_t>(m_operationCode) << 3) |
|
||||||
|
(static_cast<uint8_t>(m_authorativeAnswer) << 2) |
|
||||||
|
(static_cast<uint8_t>(m_truncation) << 1) |
|
||||||
|
(static_cast<uint8_t>(m_recursionDesired) << 0);
|
||||||
|
data.append(flags);
|
||||||
|
|
||||||
|
flags =
|
||||||
|
(static_cast<uint8_t>(m_recursionAvailable) << 7) |
|
||||||
|
(static_cast<uint8_t>(m_zero) << 4) |
|
||||||
|
(static_cast<uint8_t>(m_responseCode) << 0);
|
||||||
|
data.append(flags);
|
||||||
|
|
||||||
|
data.append(static_cast<uint16_t>(GetQueryCount()));
|
||||||
|
data.append(static_cast<uint16_t>(GetAnswerCount()));
|
||||||
|
data.append(static_cast<uint16_t>(GetAuthorityCount()));
|
||||||
|
data.append(static_cast<uint16_t>(GetAdditionalRecordsCount()));
|
||||||
|
|
||||||
|
for (const QueryImpl& q : m_queries)
|
||||||
|
data.append(q.GetData());
|
||||||
|
for (const ResourceRecordImpl& r : m_answers)
|
||||||
|
data.append(r.GetData());
|
||||||
|
for (const ResourceRecordImpl& r : m_authorities)
|
||||||
|
data.append(r.GetData());
|
||||||
|
for (const ResourceRecordImpl& r : m_additionalRecords)
|
||||||
|
data.append(r.GetData());
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Packet::GetIdentifier() const
|
||||||
|
{
|
||||||
|
return m_identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Packet::GetQuery() const
|
||||||
|
{
|
||||||
|
return m_query;
|
||||||
|
}
|
||||||
|
|
||||||
|
OperationCode::type Packet::GetOperationCode() const
|
||||||
|
{
|
||||||
|
return m_operationCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Packet::GetAuthorativeAnswer() const
|
||||||
|
{
|
||||||
|
return m_authorativeAnswer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Packet::GetTruncation() const
|
||||||
|
{
|
||||||
|
return m_truncation;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Packet::GetRecursionDesired() const
|
||||||
|
{
|
||||||
|
return m_recursionDesired;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Packet::GetRecursionAvailable() const
|
||||||
|
{
|
||||||
|
return m_recursionAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Packet::GetZero() const
|
||||||
|
{
|
||||||
|
return m_zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResponseCode::type Packet::GetResponseCode() const
|
||||||
|
{
|
||||||
|
return m_responseCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<QueryImpl> Packet::GetQueries() const
|
||||||
|
{
|
||||||
|
return m_queries;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ResourceRecordImpl> Packet::GetAnswers() const
|
||||||
|
{
|
||||||
|
return m_answers;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ResourceRecordImpl> Packet::GetAuthorities() const
|
||||||
|
{
|
||||||
|
return m_authorities;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ResourceRecordImpl> Packet::GetAdditionalRecords() const
|
||||||
|
{
|
||||||
|
return m_additionalRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Packet::GetQueryCount() const
|
||||||
|
{
|
||||||
|
return static_cast<unsigned>(m_queries.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Packet::GetAnswerCount() const
|
||||||
|
{
|
||||||
|
return static_cast<unsigned>(m_answers.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Packet::GetAuthorityCount() const
|
||||||
|
{
|
||||||
|
return static_cast<unsigned>(m_authorities.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Packet::GetAdditionalRecordsCount() const
|
||||||
|
{
|
||||||
|
return static_cast<unsigned>(m_additionalRecords.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::SetIdentifier(uint16_t identifier)
|
||||||
|
{
|
||||||
|
m_identifier = identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::SetQuery(bool query)
|
||||||
|
{
|
||||||
|
m_query = query;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::SetOperationCode(OperationCode::type operationCode)
|
||||||
|
{
|
||||||
|
m_operationCode = operationCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::SetAuthorativeAnswer(bool authorativeAnswer)
|
||||||
|
{
|
||||||
|
m_authorativeAnswer = authorativeAnswer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::SetTruncation(bool truncation)
|
||||||
|
{
|
||||||
|
m_truncation = truncation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::SetRecursionDesired(bool recursionDesired)
|
||||||
|
{
|
||||||
|
m_recursionDesired = recursionDesired;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::SetRecursionAvailable(bool recursionAvailable)
|
||||||
|
{
|
||||||
|
m_recursionAvailable = recursionAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::SetZero(uint8_t zero)
|
||||||
|
{
|
||||||
|
m_zero = zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::SetResponseCode(ResponseCode::type responseCode)
|
||||||
|
{
|
||||||
|
m_responseCode = responseCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::AddQuery(const QueryImpl& query)
|
||||||
|
{
|
||||||
|
m_queries.emplace_back(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::AddAnswer(const ResourceRecordImpl& record)
|
||||||
|
{
|
||||||
|
m_answers.emplace_back(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::AddAuthority(const ResourceRecordImpl& record)
|
||||||
|
{
|
||||||
|
m_authorities.emplace_back(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::AddAdditionalRecords(const ResourceRecordImpl& record)
|
||||||
|
{
|
||||||
|
m_additionalRecords.emplace_back(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& stream, const Packet& packet)
|
||||||
|
{
|
||||||
|
stream << "Packet (\n";
|
||||||
|
stream << " identifier = " << packet.m_identifier
|
||||||
|
<< ", query = " << packet.m_query
|
||||||
|
<< ", operationCode = " << static_cast<int>(packet.m_operationCode)
|
||||||
|
<< ", authorativeAnswer = " << packet.m_authorativeAnswer
|
||||||
|
<< ", truncation = " << packet.m_truncation
|
||||||
|
<< ", recursionDesired = " << packet.m_recursionDesired << "\n";
|
||||||
|
stream << " recursionAvailable = " << packet.m_recursionAvailable
|
||||||
|
<< ", zero = " << packet.m_zero
|
||||||
|
<< ", responseCode = " << static_cast<int>(packet.m_responseCode) << "\n";
|
||||||
|
for (const QueryImpl& q : packet.m_queries)
|
||||||
|
stream << " Query: " << q << "\n";
|
||||||
|
for (const ResourceRecordImpl& r : packet.m_answers)
|
||||||
|
stream << " Answer: " << r << "\n";
|
||||||
|
for (const ResourceRecordImpl& r : packet.m_authorities)
|
||||||
|
stream << " Authority: " << r << "\n";
|
||||||
|
for (const ResourceRecordImpl& r : packet.m_additionalRecords)
|
||||||
|
stream << " AdditionalRecord: " << r << "\n";
|
||||||
|
stream << ")\n";
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
#ifndef NETWORK_DNS_PACKET_H
|
||||||
|
#define NETWORK_DNS_PACKET_H
|
||||||
|
|
||||||
|
#include "Data.h"
|
||||||
|
#include "DataReader.h"
|
||||||
|
#include "OperationCode.h"
|
||||||
|
#include "QueryImpl.h"
|
||||||
|
#include "ResourceRecordImpl.h"
|
||||||
|
#include "ResponseCode.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class Packet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Packet();
|
||||||
|
Packet(DataReader reader, unsigned pos);
|
||||||
|
|
||||||
|
Data GetData() const;
|
||||||
|
|
||||||
|
uint16_t GetIdentifier() const;
|
||||||
|
bool GetQuery() const;
|
||||||
|
OperationCode::type GetOperationCode() const;
|
||||||
|
bool GetAuthorativeAnswer() const;
|
||||||
|
bool GetTruncation() const;
|
||||||
|
bool GetRecursionDesired() const;
|
||||||
|
bool GetRecursionAvailable() const;
|
||||||
|
uint8_t GetZero() const;
|
||||||
|
ResponseCode::type GetResponseCode() const;
|
||||||
|
|
||||||
|
std::vector<QueryImpl> GetQueries() const;
|
||||||
|
std::vector<ResourceRecordImpl> GetAnswers() const;
|
||||||
|
std::vector<ResourceRecordImpl> GetAuthorities() const;
|
||||||
|
std::vector<ResourceRecordImpl> GetAdditionalRecords() const;
|
||||||
|
|
||||||
|
unsigned GetQueryCount() const;
|
||||||
|
unsigned GetAnswerCount() const;
|
||||||
|
unsigned GetAuthorityCount() const;
|
||||||
|
unsigned GetAdditionalRecordsCount() const;
|
||||||
|
|
||||||
|
void SetIdentifier(uint16_t identifier);
|
||||||
|
void SetQuery(bool query);
|
||||||
|
void SetOperationCode(OperationCode::type oerationCode);
|
||||||
|
void SetAuthorativeAnswer(bool authorativeAnswer);
|
||||||
|
void SetTruncation(bool truncation);
|
||||||
|
void SetRecursionDesired(bool recursionDesired);
|
||||||
|
void SetRecursionAvailable(bool recursionAvailable);
|
||||||
|
void SetZero(uint8_t zero);
|
||||||
|
void SetResponseCode(ResponseCode::type responseCode);
|
||||||
|
|
||||||
|
void AddQuery(const QueryImpl& query);
|
||||||
|
void AddAnswer(const ResourceRecordImpl& record);
|
||||||
|
void AddAuthority(const ResourceRecordImpl& record);
|
||||||
|
void AddAdditionalRecords(const ResourceRecordImpl& record);
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream& stream, const Packet& packet);
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned m_identifier : 16;
|
||||||
|
unsigned m_query : 1;
|
||||||
|
unsigned m_authorativeAnswer : 1;
|
||||||
|
unsigned m_truncation : 1;
|
||||||
|
unsigned m_recursionDesired : 1;
|
||||||
|
unsigned m_recursionAvailable : 1;
|
||||||
|
unsigned m_zero : 3;
|
||||||
|
OperationCode::type m_operationCode;
|
||||||
|
ResponseCode::type m_responseCode;
|
||||||
|
std::vector<QueryImpl> m_queries;
|
||||||
|
std::vector<ResourceRecordImpl> m_answers;
|
||||||
|
std::vector<ResourceRecordImpl> m_authorities;
|
||||||
|
std::vector<ResourceRecordImpl> m_additionalRecords;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // NETWORK_DNS_PACKET_H
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#include "Dns/Query.h"
|
||||||
|
#include "QueryImpl.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
Query::Query() :
|
||||||
|
m_pQueryImpl(new QueryImpl())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Query::GetUnicast() const
|
||||||
|
{
|
||||||
|
return m_pQueryImpl->GetUnicast();
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryType::type Query::GetType() const
|
||||||
|
{
|
||||||
|
return m_pQueryImpl->GetType();
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryClass::type Query::GetClass() const
|
||||||
|
{
|
||||||
|
return m_pQueryImpl->GetClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
Name Query::GetName() const
|
||||||
|
{
|
||||||
|
return Name(m_pQueryImpl->GetName());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Query::SetUnicast(bool unicast)
|
||||||
|
{
|
||||||
|
m_pQueryImpl->SetUnicast(unicast);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Query::SetType(QueryType::type type)
|
||||||
|
{
|
||||||
|
m_pQueryImpl->SetType(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Query::SetClass(QueryClass::type class_)
|
||||||
|
{
|
||||||
|
m_pQueryImpl->SetClass(class_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Query::SetName(const Name& name)
|
||||||
|
{
|
||||||
|
m_pQueryImpl->SetName(*name.PImpl());
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryImpl* Query::PImpl() const
|
||||||
|
{
|
||||||
|
return m_pQueryImpl.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
#include "QueryImpl.h"
|
||||||
|
#include "MalformedPacket.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
QueryImpl::QueryImpl() :
|
||||||
|
m_unicast(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QueryImpl::GetUnicast() const
|
||||||
|
{
|
||||||
|
return m_unicast;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryType::type QueryImpl::GetType() const
|
||||||
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryClass::type QueryImpl::GetClass() const
|
||||||
|
{
|
||||||
|
return m_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
NameImpl QueryImpl::GetName() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QueryImpl::SetUnicast(bool unicast)
|
||||||
|
{
|
||||||
|
m_unicast = unicast;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QueryImpl::SetType(QueryType::type type)
|
||||||
|
{
|
||||||
|
m_type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QueryImpl::SetClass(QueryClass::type class_)
|
||||||
|
{
|
||||||
|
m_class = class_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QueryImpl::SetName(const NameImpl& name)
|
||||||
|
{
|
||||||
|
m_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data QueryImpl::GetData() const
|
||||||
|
{
|
||||||
|
Data data = m_name.GetData();
|
||||||
|
data.append(static_cast<uint16_t>(m_type));
|
||||||
|
uint16_t classField = static_cast<uint16_t>(m_class);
|
||||||
|
if (m_unicast)
|
||||||
|
classField |= (static_cast<uint16_t>(1) << 15);
|
||||||
|
data.append(classField);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned QueryImpl::ReadFromData(DataReader reader, unsigned pos)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
NameImpl newName;
|
||||||
|
pos = newName.ReadFromData(reader, pos);
|
||||||
|
QueryType::type newType = static_cast<QueryType::type>(reader.Read16(pos));
|
||||||
|
bool newUnicast = false;
|
||||||
|
|
||||||
|
uint16_t classField = reader.Read16(pos);
|
||||||
|
if (classField & (static_cast<uint16_t>(1) << 15))
|
||||||
|
{
|
||||||
|
classField ^= static_cast<uint16_t>(1) << 15;
|
||||||
|
newUnicast = true;
|
||||||
|
}
|
||||||
|
QueryClass::type newClass = static_cast<QueryClass::type>(classField);
|
||||||
|
|
||||||
|
std::swap(m_name, newName);
|
||||||
|
std::swap(m_type, newType);
|
||||||
|
std::swap(m_class, newClass);
|
||||||
|
std::swap(m_unicast, newUnicast);
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
catch (const DataReaderOutOfBounds& droob)
|
||||||
|
{
|
||||||
|
throw MalformedPacket();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& stream, const QueryImpl& query)
|
||||||
|
{
|
||||||
|
return stream << "Query(" << query.m_name
|
||||||
|
<< ", type = " << static_cast<int>(query.m_type)
|
||||||
|
<< ", class = " << static_cast<int>(query.m_class)
|
||||||
|
<< ", " << (query.m_unicast ? "Unicast" : "Multicast") << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#ifndef NETWORK_DNS_QUERYIMPL_H
|
||||||
|
#define NETWORK_DNS_QUERYIMPL_H
|
||||||
|
|
||||||
|
#include "Data.h"
|
||||||
|
#include "DataReader.h"
|
||||||
|
#include "NameImpl.h"
|
||||||
|
#include "Dns/QueryClass.h"
|
||||||
|
#include "Dns/QueryType.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class QueryImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QueryImpl();
|
||||||
|
|
||||||
|
bool GetUnicast() const;
|
||||||
|
QueryType::type GetType() const;
|
||||||
|
QueryClass::type GetClass() const;
|
||||||
|
NameImpl GetName() const;
|
||||||
|
|
||||||
|
void SetUnicast(bool unicast);
|
||||||
|
void SetType(QueryType::type type);
|
||||||
|
void SetClass(QueryClass::type class_);
|
||||||
|
void SetName(const NameImpl& name);
|
||||||
|
|
||||||
|
Data GetData() const;
|
||||||
|
|
||||||
|
unsigned ReadFromData(DataReader reader, unsigned pos);
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream & stream, const QueryImpl& query);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_unicast;
|
||||||
|
NameImpl m_name;
|
||||||
|
QueryType::type m_type;
|
||||||
|
QueryClass::type m_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // NETWORK_DNS_QUERYIMPL_H
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
#include "Dns/ResourceRecord.h"
|
||||||
|
#include "ResourceRecordImpl.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
ResourceRecord::ResourceRecord(std::shared_ptr<ResourceRecordImpl> pResourceRecordImpl) :
|
||||||
|
m_pResourceRecordImpl(pResourceRecordImpl)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Name ResourceRecord::GetName() const
|
||||||
|
{
|
||||||
|
return Name(m_pResourceRecordImpl->GetName());
|
||||||
|
}
|
||||||
|
|
||||||
|
Type::type ResourceRecord::GetType() const
|
||||||
|
{
|
||||||
|
return m_pResourceRecordImpl->GetType();
|
||||||
|
}
|
||||||
|
|
||||||
|
Class::type ResourceRecord::GetClass() const
|
||||||
|
{
|
||||||
|
return m_pResourceRecordImpl->GetClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ResourceRecord::GetTTL() const
|
||||||
|
{
|
||||||
|
return m_pResourceRecordImpl->GetTTL();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> ResourceRecord::GetResourceData() const
|
||||||
|
{
|
||||||
|
Data data = m_pResourceRecordImpl->GetResourceData();
|
||||||
|
|
||||||
|
const uint8_t* ptr = data.GetPtr();
|
||||||
|
int length = data.GetLength();
|
||||||
|
|
||||||
|
std::vector<uint8_t> returnValue(length);
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
returnValue[i] = ptr[i];
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> ResourceRecord::GetData() const
|
||||||
|
{
|
||||||
|
Data data = m_pResourceRecordImpl->GetData();
|
||||||
|
|
||||||
|
const uint8_t* ptr = data.GetPtr();
|
||||||
|
int length = data.GetLength();
|
||||||
|
|
||||||
|
std::vector<uint8_t> returnValue(length);
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
returnValue[i] = ptr[i];
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceRecord::SetName(const Name& name)
|
||||||
|
{
|
||||||
|
return m_pResourceRecordImpl->SetName(*name.PImpl());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceRecord::SetType(Type::type type)
|
||||||
|
{
|
||||||
|
return m_pResourceRecordImpl->SetType(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceRecord::SetClass(Class::type class_)
|
||||||
|
{
|
||||||
|
return m_pResourceRecordImpl->SetClass(class_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceRecord::SetTTL(uint32_t ttl)
|
||||||
|
{
|
||||||
|
return m_pResourceRecordImpl->SetTTL(ttl);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
#include "ResourceRecordImpl.h"
|
||||||
|
#include "MalformedPacket.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
NameImpl ResourceRecordImpl::GetName() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type::type ResourceRecordImpl::GetType() const
|
||||||
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
Class::type ResourceRecordImpl::GetClass() const
|
||||||
|
{
|
||||||
|
return m_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ResourceRecordImpl::GetTTL() const
|
||||||
|
{
|
||||||
|
return m_ttl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data ResourceRecordImpl::GetResourceData() const
|
||||||
|
{
|
||||||
|
return m_resourceData;
|
||||||
|
}
|
||||||
|
|
||||||
|
NameImpl ResourceRecordImpl::GetResourceDataName() const
|
||||||
|
{
|
||||||
|
return m_resourceDataName;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data ResourceRecordImpl::GetData() const
|
||||||
|
{
|
||||||
|
Data data = m_name.GetData();
|
||||||
|
data.append(static_cast<uint16_t>(m_type));
|
||||||
|
data.append(static_cast<uint16_t>(m_class));
|
||||||
|
data.append(static_cast<uint32_t>(m_ttl));
|
||||||
|
data.append(static_cast<uint16_t>(m_resourceData.GetLength()));
|
||||||
|
data.append(m_resourceData);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceRecordImpl::SetName(const NameImpl& name)
|
||||||
|
{
|
||||||
|
m_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceRecordImpl::SetType(Type::type type)
|
||||||
|
{
|
||||||
|
m_type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceRecordImpl::SetClass(Class::type dnsClass)
|
||||||
|
{
|
||||||
|
m_class = dnsClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceRecordImpl::SetTTL(uint32_t ttl)
|
||||||
|
{
|
||||||
|
m_ttl = ttl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceRecordImpl::SetData(const Data& resourceData)
|
||||||
|
{
|
||||||
|
m_resourceData = resourceData;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned ResourceRecordImpl::ReadFromData(DataReader reader, unsigned pos)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
NameImpl newName;
|
||||||
|
unsigned oldpos = pos;
|
||||||
|
pos = newName.ReadFromData(reader, pos);
|
||||||
|
Type::type newType = static_cast<Type::type>(reader.Read16(pos));
|
||||||
|
Class::type newClass = static_cast<Class::type>(reader.Read16(pos));
|
||||||
|
uint32_t newTTL = reader.Read32(pos);
|
||||||
|
Data newRData;
|
||||||
|
unsigned rdlength = reader.Read16(pos);
|
||||||
|
for (size_t i = 0; i < rdlength; i++)
|
||||||
|
newRData.append(reader.Read8(pos));
|
||||||
|
std::swap(m_name, newName);
|
||||||
|
std::swap(m_type, newType);
|
||||||
|
std::swap(m_class, newClass);
|
||||||
|
std::swap(m_ttl, newTTL);
|
||||||
|
std::swap(m_resourceData, newRData);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_resourceDataName.ReadFromData(reader, pos - m_resourceData.GetLength());
|
||||||
|
}
|
||||||
|
catch (MalformedPacket& mp)
|
||||||
|
{
|
||||||
|
m_resourceDataName = NameImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
catch (const DataReaderOutOfBounds& droob)
|
||||||
|
{
|
||||||
|
throw MalformedPacket();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& stream, const ResourceRecordImpl& record)
|
||||||
|
{
|
||||||
|
return stream << "ResourceRecord(" << record.m_name
|
||||||
|
<< ", type = " << static_cast<int>(record.m_type)
|
||||||
|
<< ", class = " << static_cast<int>(record.m_class)
|
||||||
|
<< ", ttl = " << record.m_ttl
|
||||||
|
<< ", rdata = " << record.m_resourceData << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef NETWORK_DNS_RESOURCERECORD_H
|
||||||
|
#define NETWORK_DNS_RESOURCERECORD_H
|
||||||
|
|
||||||
|
#include "Data.h"
|
||||||
|
#include "DataReader.h"
|
||||||
|
#include "NameImpl.h"
|
||||||
|
#include "Dns/Class.h"
|
||||||
|
#include "Dns/Type.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class ResourceRecordImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NameImpl GetName() const;
|
||||||
|
Type::type GetType() const;
|
||||||
|
Class::type GetClass() const;
|
||||||
|
uint32_t GetTTL() const;
|
||||||
|
Data GetResourceData() const;
|
||||||
|
NameImpl GetResourceDataName() const;
|
||||||
|
|
||||||
|
Data GetData() const;
|
||||||
|
|
||||||
|
void SetName(const NameImpl& name);
|
||||||
|
void SetType(Type::type type);
|
||||||
|
void SetClass(Class::type dnsClass);
|
||||||
|
void SetTTL(uint32_t ttl);
|
||||||
|
void SetData(const Data& resourceData);
|
||||||
|
|
||||||
|
unsigned ReadFromData(DataReader reader, unsigned pos);
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream& stream, const ResourceRecordImpl& record);
|
||||||
|
|
||||||
|
private:
|
||||||
|
NameImpl m_name;
|
||||||
|
Type::type m_type;
|
||||||
|
Class::type m_class;
|
||||||
|
uint32_t m_ttl;
|
||||||
|
Data m_resourceData;
|
||||||
|
NameImpl m_resourceDataName;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // NETWORK_DNS_RESOURCERECORD_H
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef NETWORK_DNS_RESPONSECODE_H
|
||||||
|
#define NETWORK_DNS_RESPONSECODE_H
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class ResponseCode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum type
|
||||||
|
{
|
||||||
|
NO_ERROR = 0,
|
||||||
|
FORMAT_ERROR = 1,
|
||||||
|
SERVER_FAILURE = 2,
|
||||||
|
NAME_ERROR = 3,
|
||||||
|
NOT_IMPLEMENTED = 4,
|
||||||
|
REFUSED = 5
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // NETWORK_DNS_RESPONSECODE_H
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef CLASS_H
|
||||||
|
#define CLASS_H
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class Class
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum type
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
IN = 1,
|
||||||
|
CS = 2,
|
||||||
|
CH = 3,
|
||||||
|
HS = 4
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // CLASS_H
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef MULTICASTDNSCLIENT_H
|
||||||
|
#define MULTICASTDNSCLIENT_H
|
||||||
|
|
||||||
|
#include "Query.h"
|
||||||
|
#include "ResourceRecord.h"
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class MulticastDnsClientImpl;
|
||||||
|
|
||||||
|
class MulticastDnsClient
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MulticastDnsClient(std::function<void(const std::vector<ResourceRecord>&)> callback);
|
||||||
|
~MulticastDnsClient();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void Query(const Dns::Query& query);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Callback(const std::vector<ResourceRecordImpl>& data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<MulticastDnsClientImpl> m_pMulticastDnsClientImpl;
|
||||||
|
std::function<void(const std::vector<ResourceRecord>&)> m_callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // MULTICASTDNSCLIENT_H
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#ifndef NAME_H
|
||||||
|
#define NAME_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class NameImpl;
|
||||||
|
|
||||||
|
class Name
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Name();
|
||||||
|
|
||||||
|
template<typename ...Args>
|
||||||
|
Name(const Args& ...args) :
|
||||||
|
Name(toStringVector(args...))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Name(const std::vector<std::string>& labels);
|
||||||
|
|
||||||
|
std::string GetFirstLabel() const;
|
||||||
|
std::string GetName() const;
|
||||||
|
bool empty() const;
|
||||||
|
bool endsWith(const Name& suffix) const;
|
||||||
|
|
||||||
|
void append(const std::string& label);
|
||||||
|
void prepend(const std::string& label);
|
||||||
|
|
||||||
|
void swap(Name& x) noexcept;
|
||||||
|
|
||||||
|
bool operator==(const Name& name) const;
|
||||||
|
bool operator!=(const Name& name) const;
|
||||||
|
bool operator<(const Name& name) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Name(std::shared_ptr<NameImpl> pNameImpl);
|
||||||
|
NameImpl* PImpl() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <class T>
|
||||||
|
std::string toString(T&& t)
|
||||||
|
{
|
||||||
|
std::stringstream s;
|
||||||
|
s << std::forward<T>(t);
|
||||||
|
return s.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class... T>
|
||||||
|
std::vector<std::string> toStringVector(T&&... args)
|
||||||
|
{
|
||||||
|
std::vector<std::string> res { toString(std::forward<T>(args))... };
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class Query;
|
||||||
|
friend class ResourceRecord;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<NameImpl> m_pNameImpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // NAME_H
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#ifndef QUERY_H
|
||||||
|
#define QUERY_H
|
||||||
|
|
||||||
|
#include "Name.h"
|
||||||
|
#include "QueryClass.h"
|
||||||
|
#include "QueryType.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class QueryImpl;
|
||||||
|
|
||||||
|
class Query
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Query();
|
||||||
|
|
||||||
|
bool GetUnicast() const;
|
||||||
|
QueryType::type GetType() const;
|
||||||
|
QueryClass::type GetClass() const;
|
||||||
|
Name GetName() const;
|
||||||
|
|
||||||
|
void SetUnicast(bool unicast);
|
||||||
|
void SetType(QueryType::type type);
|
||||||
|
void SetClass(QueryClass::type class_);
|
||||||
|
void SetName(const Name& name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QueryImpl* PImpl() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class MulticastDnsClient;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<QueryImpl> m_pQueryImpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // QUERY_H
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef QUERYCLASS_H
|
||||||
|
#define QUERYCLASS_H
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class QueryClass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum type
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
IN = 1,
|
||||||
|
CS = 2,
|
||||||
|
CH = 3,
|
||||||
|
HS = 4,
|
||||||
|
ANY = 255
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // QUERYCLASS_H
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef QUERYTYPE_H
|
||||||
|
#define QUERYTYPE_H
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class QueryType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum type
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
A = 1,
|
||||||
|
NC = 2,
|
||||||
|
MD = 3,
|
||||||
|
MF = 4,
|
||||||
|
CNAME = 5,
|
||||||
|
SOA = 6,
|
||||||
|
MB = 7,
|
||||||
|
MG = 8,
|
||||||
|
MR = 9,
|
||||||
|
NULL_ = 10,
|
||||||
|
WKS = 11,
|
||||||
|
PTR = 12,
|
||||||
|
HINFO = 13,
|
||||||
|
MINFO = 14,
|
||||||
|
MX = 15,
|
||||||
|
TXT = 16,
|
||||||
|
AXFR = 252,
|
||||||
|
MAILB = 253,
|
||||||
|
MAILA = 254,
|
||||||
|
ANY = 255
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // QUERYTYPE_H
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#ifndef RESOURCERECORD_H
|
||||||
|
#define RESOURCERECORD_H
|
||||||
|
|
||||||
|
#include "Class.h"
|
||||||
|
#include "Name.h"
|
||||||
|
#include "Type.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class ResourceRecordImpl;
|
||||||
|
|
||||||
|
class ResourceRecord
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Name GetName() const;
|
||||||
|
Type::type GetType() const;
|
||||||
|
Class::type GetClass() const;
|
||||||
|
uint32_t GetTTL() const;
|
||||||
|
|
||||||
|
std::vector<uint8_t> GetResourceData() const;
|
||||||
|
std::vector<uint8_t> GetData() const;
|
||||||
|
|
||||||
|
void SetName(const Name& name);
|
||||||
|
void SetType(Type::type type);
|
||||||
|
void SetClass(Class::type class_);
|
||||||
|
void SetTTL(uint32_t ttl);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ResourceRecord(std::shared_ptr<ResourceRecordImpl> pResourceRecordImpl);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class MulticastDnsClient;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<ResourceRecordImpl> m_pResourceRecordImpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // RESOURCERECORD_H
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef TYPE_H
|
||||||
|
#define TYPE_H
|
||||||
|
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
namespace Dns {
|
||||||
|
|
||||||
|
class Type
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum type
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
A = 1,
|
||||||
|
NC = 2,
|
||||||
|
MD = 3,
|
||||||
|
MF = 4,
|
||||||
|
CNAME = 5,
|
||||||
|
SOA = 6,
|
||||||
|
MB = 7,
|
||||||
|
MG = 8,
|
||||||
|
MR = 9,
|
||||||
|
NULL_ = 10,
|
||||||
|
WKS = 11,
|
||||||
|
PTR = 12,
|
||||||
|
HINFO = 13,
|
||||||
|
MINFO = 14,
|
||||||
|
MX = 15,
|
||||||
|
TXT = 16
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dns
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
#endif // TYPE_H
|
||||||
Reference in New Issue
Block a user