mirror of https://github.com/oxen-io/lokinet
commit
2069ca403b
@ -0,0 +1,5 @@
|
||||
#include <llarp/dns/name.hpp>
|
||||
#include <llarp/dns/rr.hpp>
|
||||
#include <llarp/dns/serialize.hpp>
|
||||
#include <llarp/dns/message.hpp>
|
||||
#include <llarp/dns/server.hpp>
|
@ -0,0 +1,97 @@
|
||||
#ifndef LLARP_DNS_MESSAGE_HPP
|
||||
#define LLARP_DNS_MESSAGE_HPP
|
||||
#include <llarp/dns/serialize.hpp>
|
||||
#include <llarp/dns/rr.hpp>
|
||||
#include <llarp/dns/question.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dns
|
||||
{
|
||||
using MsgID_t = uint16_t;
|
||||
using Fields_t = uint16_t;
|
||||
using Count_t = uint16_t;
|
||||
|
||||
struct MessageHeader : public Serialize
|
||||
{
|
||||
const static size_t Size = 12;
|
||||
|
||||
MessageHeader() = default;
|
||||
|
||||
MsgID_t id;
|
||||
Fields_t fields;
|
||||
Count_t qd_count;
|
||||
Count_t an_count;
|
||||
Count_t ns_count;
|
||||
Count_t ar_count;
|
||||
|
||||
bool
|
||||
Encode(llarp_buffer_t* buf) const override;
|
||||
|
||||
bool
|
||||
Decode(llarp_buffer_t* buf) override;
|
||||
|
||||
bool
|
||||
operator==(const MessageHeader& other) const
|
||||
{
|
||||
return id == other.id && fields == other.fields
|
||||
&& qd_count == other.qd_count && an_count == other.an_count
|
||||
&& ns_count == other.ns_count && ar_count == other.ar_count;
|
||||
}
|
||||
};
|
||||
|
||||
struct Message : public Serialize
|
||||
{
|
||||
Message(const MessageHeader& hdr);
|
||||
|
||||
Message(Message&& other);
|
||||
Message(const Message& other);
|
||||
|
||||
void
|
||||
UpdateHeader();
|
||||
|
||||
void
|
||||
AddNXReply();
|
||||
|
||||
void
|
||||
AddINReply(llarp::huint32_t addr);
|
||||
|
||||
void
|
||||
AddAReply(std::string name);
|
||||
|
||||
bool
|
||||
Encode(llarp_buffer_t* buf) const override;
|
||||
|
||||
bool
|
||||
Decode(llarp_buffer_t* buf) override;
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& out, const Message& msg)
|
||||
{
|
||||
out << "[dns message id=" << std::hex << msg.hdr_id
|
||||
<< " fields=" << msg.hdr_fields << " questions=[ ";
|
||||
for(const auto& qd : msg.questions)
|
||||
out << qd << ", ";
|
||||
out << "] answers=[ ";
|
||||
for(const auto& an : msg.answers)
|
||||
out << an << ", ";
|
||||
out << "] nameserver=[ ";
|
||||
for(const auto& ns : msg.authorities)
|
||||
out << ns << ", ";
|
||||
out << "] additional=[ ";
|
||||
for(const auto& ar : msg.additional)
|
||||
out << ar << ", ";
|
||||
return out << "]";
|
||||
}
|
||||
|
||||
MsgID_t hdr_id;
|
||||
Fields_t hdr_fields;
|
||||
std::vector< Question > questions;
|
||||
std::vector< ResourceRecord > answers;
|
||||
std::vector< ResourceRecord > authorities;
|
||||
std::vector< ResourceRecord > additional;
|
||||
};
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -0,0 +1,28 @@
|
||||
#ifndef LLARP_DNS_NAME_HPP
|
||||
#define LLARP_DNS_NAME_HPP
|
||||
|
||||
#include <string>
|
||||
#include <llarp/buffer.h>
|
||||
#include <llarp/net_int.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dns
|
||||
{
|
||||
using Name_t = std::string;
|
||||
|
||||
/// decode name from buffer
|
||||
bool
|
||||
DecodeName(llarp_buffer_t* buf, Name_t& name);
|
||||
|
||||
/// encode name to buffer
|
||||
bool
|
||||
EncodeName(llarp_buffer_t* buf, const Name_t& name);
|
||||
|
||||
bool
|
||||
DecodePTR(const Name_t& name, huint32_t& ip);
|
||||
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -0,0 +1,4 @@
|
||||
#ifndef LLARP_DNS_QUERY_HPP
|
||||
#define LLARP_DNS_QUERY_HPP
|
||||
|
||||
#endif
|
@ -0,0 +1,46 @@
|
||||
#ifndef LLARP_DNS_QUESTION_HPP
|
||||
#define LLARP_DNS_QUESTION_HPP
|
||||
#include <llarp/dns/serialize.hpp>
|
||||
#include <llarp/dns/name.hpp>
|
||||
#include <llarp/net_int.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dns
|
||||
{
|
||||
using QType_t = uint16_t;
|
||||
using QClass_t = uint16_t;
|
||||
|
||||
struct Question : public Serialize
|
||||
{
|
||||
Question() = default;
|
||||
Question(Question&& other);
|
||||
Question(const Question& other);
|
||||
bool
|
||||
Encode(llarp_buffer_t* buf) const override;
|
||||
|
||||
bool
|
||||
Decode(llarp_buffer_t* buf) override;
|
||||
|
||||
bool
|
||||
operator==(const Question& other) const
|
||||
{
|
||||
return qname == other.qname && qtype == other.qtype
|
||||
&& qclass == other.qclass;
|
||||
}
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& out, const Question& q)
|
||||
{
|
||||
return out << "qname=" << q.qname << " qtype=" << (int)q.qtype
|
||||
<< " qclass=" << (int)q.qclass;
|
||||
}
|
||||
|
||||
Name_t qname;
|
||||
QType_t qtype;
|
||||
QClass_t qclass;
|
||||
};
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -0,0 +1,47 @@
|
||||
#ifndef LLARP_DNS_RR_HPP
|
||||
#define LLARP_DNS_RR_HPP
|
||||
#include <llarp/dns/name.hpp>
|
||||
#include <llarp/dns/serialize.hpp>
|
||||
#include <llarp/net_int.hpp>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dns
|
||||
{
|
||||
using RRClass_t = uint16_t;
|
||||
using RRType_t = uint16_t;
|
||||
using RR_RData_t = std::vector< byte_t >;
|
||||
using RR_TTL_t = uint32_t;
|
||||
|
||||
struct ResourceRecord : public Serialize
|
||||
{
|
||||
ResourceRecord() = default;
|
||||
ResourceRecord(const ResourceRecord& other);
|
||||
ResourceRecord(ResourceRecord&& other);
|
||||
|
||||
bool
|
||||
Encode(llarp_buffer_t* buf) const override;
|
||||
|
||||
bool
|
||||
Decode(llarp_buffer_t* buf) override;
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& out, const ResourceRecord& rr)
|
||||
{
|
||||
return out << "[RR name=" << rr.rr_name << " type=" << rr.rr_type
|
||||
<< " class=" << rr.rr_class << " ttl=" << rr.ttl
|
||||
<< " rdata=[" << rr.rData.size() << " bytes]";
|
||||
}
|
||||
|
||||
Name_t rr_name;
|
||||
RRType_t rr_type;
|
||||
RRClass_t rr_class;
|
||||
RR_TTL_t ttl;
|
||||
RR_RData_t rData;
|
||||
};
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -0,0 +1,33 @@
|
||||
#ifndef LLARP_DNS_SERIALIZE_HPP
|
||||
#define LLARP_DNS_SERIALIZE_HPP
|
||||
#include <llarp/buffer.h>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dns
|
||||
{
|
||||
/// base type for serializable dns entities
|
||||
struct Serialize
|
||||
{
|
||||
virtual ~Serialize() = default;
|
||||
|
||||
/// encode entity to buffer
|
||||
virtual bool
|
||||
Encode(llarp_buffer_t* buf) const = 0;
|
||||
|
||||
/// decode entity from buffer
|
||||
virtual bool
|
||||
Decode(llarp_buffer_t* buf) = 0;
|
||||
};
|
||||
|
||||
bool
|
||||
EncodeRData(llarp_buffer_t* buf, const std::vector< byte_t >& rdata);
|
||||
|
||||
bool
|
||||
DecodeRData(llarp_buffer_t* buf, std::vector< byte_t >& rdata);
|
||||
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -0,0 +1,101 @@
|
||||
#ifndef LLARP_DNS_SERVER_HPP
|
||||
#define LLARP_DNS_SERVER_HPP
|
||||
#include <llarp/string_view.hpp>
|
||||
#include <llarp/dns/message.hpp>
|
||||
|
||||
#include <llarp/ev.h>
|
||||
#include <llarp/net.hpp>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dns
|
||||
{
|
||||
/// handler of dns query hooking
|
||||
struct IQueryHandler
|
||||
{
|
||||
/// return true if we should hook this message
|
||||
virtual bool
|
||||
ShouldHookDNSMessage(const Message& msg) const = 0;
|
||||
|
||||
/// handle a hooked message
|
||||
virtual bool
|
||||
HandleHookedDNSMessage(Message query,
|
||||
std::function< void(Message) > sendReply) = 0;
|
||||
};
|
||||
|
||||
struct Proxy
|
||||
{
|
||||
Proxy(llarp_ev_loop* loop, IQueryHandler* handler);
|
||||
|
||||
bool
|
||||
Start(const llarp::Addr& addr,
|
||||
const std::vector< llarp::Addr >& resolvers);
|
||||
|
||||
void
|
||||
Stop();
|
||||
|
||||
private:
|
||||
/// low level packet handler
|
||||
static void
|
||||
HandleUDPRecv_client(llarp_udp_io*, const struct sockaddr*,
|
||||
llarp_buffer_t);
|
||||
static void
|
||||
HandleUDPRecv_server(llarp_udp_io*, const struct sockaddr*,
|
||||
llarp_buffer_t);
|
||||
|
||||
/// low level ticker
|
||||
static void
|
||||
HandleTick(llarp_udp_io*);
|
||||
|
||||
void
|
||||
Tick(llarp_time_t now);
|
||||
|
||||
void
|
||||
HandlePktClient(llarp::Addr from, llarp_buffer_t* buf);
|
||||
|
||||
void
|
||||
HandlePktServer(llarp::Addr from, llarp_buffer_t* buf);
|
||||
|
||||
void
|
||||
SendMessageTo(llarp::Addr to, Message msg);
|
||||
|
||||
llarp::Addr
|
||||
PickRandomResolver() const;
|
||||
|
||||
private:
|
||||
llarp_udp_io m_Server;
|
||||
llarp_udp_io m_Client;
|
||||
llarp_ev_loop* m_Loop;
|
||||
IQueryHandler* m_QueryHandler;
|
||||
std::vector< llarp::Addr > m_Resolvers;
|
||||
|
||||
struct TX
|
||||
{
|
||||
MsgID_t txid;
|
||||
llarp::Addr from;
|
||||
|
||||
bool
|
||||
operator==(const TX& other) const
|
||||
{
|
||||
return txid == other.txid && from == other.from;
|
||||
}
|
||||
|
||||
struct Hash
|
||||
{
|
||||
size_t
|
||||
operator()(const TX& t) const noexcept
|
||||
{
|
||||
return t.txid ^ llarp::Addr::Hash()(t.from);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// maps tx to who to send reply to
|
||||
std::unordered_map< TX, llarp::Addr, TX::Hash > m_Forwarded;
|
||||
};
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -0,0 +1,23 @@
|
||||
#ifndef LLARP_DNS_STRING_HPP
|
||||
#define LLARP_DNS_STRING_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dns
|
||||
{
|
||||
using name_t = std::string;
|
||||
|
||||
/// decode name from buffer
|
||||
bool
|
||||
decode_name(llarp_buffer_t* buf, name_t& name);
|
||||
|
||||
/// encode name to buffer
|
||||
bool
|
||||
encode_name(llarp_buffer_t* buf, const name_t& name);
|
||||
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -0,0 +1,199 @@
|
||||
#ifndef LLARP_NET_INT_HPP
|
||||
#define LLARP_NET_INT_HPP
|
||||
|
||||
// for addrinfo
|
||||
#ifndef _WIN32
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define inet_aton(x, y) inet_pton(AF_INET, x, y)
|
||||
#endif
|
||||
|
||||
#include <stdlib.h> // for itoa
|
||||
#include <iostream>
|
||||
#include <llarp/net.h>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
// clang-format off
|
||||
|
||||
struct huint32_t
|
||||
{
|
||||
uint32_t h;
|
||||
|
||||
constexpr huint32_t
|
||||
operator &(huint32_t x) const { return huint32_t{uint32_t(h & x.h)}; }
|
||||
constexpr huint32_t
|
||||
operator |(huint32_t x) const { return huint32_t{uint32_t(h | x.h)}; }
|
||||
constexpr huint32_t
|
||||
operator ^(huint32_t x) const { return huint32_t{uint32_t(h ^ x.h)}; }
|
||||
|
||||
constexpr huint32_t
|
||||
operator ~() const { return huint32_t{uint32_t(~h)}; }
|
||||
|
||||
inline huint32_t operator ++() { ++h; return *this; }
|
||||
inline huint32_t operator --() { --h; return *this; }
|
||||
|
||||
constexpr bool operator <(huint32_t x) const { return h < x.h; }
|
||||
constexpr bool operator ==(huint32_t x) const { return h == x.h; }
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& out, const huint32_t& a)
|
||||
{
|
||||
uint32_t n = htonl(a.h);
|
||||
char tmp[INET_ADDRSTRLEN] = {0};
|
||||
if(inet_ntop(AF_INET, (void*)&n, tmp, sizeof(tmp)))
|
||||
{
|
||||
out << tmp;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
struct Hash
|
||||
{
|
||||
inline size_t
|
||||
operator ()(huint32_t x) const
|
||||
{
|
||||
return std::hash< uint32_t >{}(x.h);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
struct nuint32_t
|
||||
{
|
||||
uint32_t n;
|
||||
|
||||
constexpr nuint32_t
|
||||
operator &(nuint32_t x) const { return nuint32_t{uint32_t(n & x.n)}; }
|
||||
constexpr nuint32_t
|
||||
operator |(nuint32_t x) const { return nuint32_t{uint32_t(n | x.n)}; }
|
||||
constexpr nuint32_t
|
||||
operator ^(nuint32_t x) const { return nuint32_t{uint32_t(n ^ x.n)}; }
|
||||
|
||||
constexpr nuint32_t
|
||||
operator ~() const { return nuint32_t{uint32_t(~n)}; }
|
||||
|
||||
inline nuint32_t operator ++() { ++n; return *this; }
|
||||
inline nuint32_t operator --() { --n; return *this; }
|
||||
|
||||
constexpr bool operator <(nuint32_t x) const { return n < x.n; }
|
||||
constexpr bool operator ==(nuint32_t x) const { return n == x.n; }
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& out, const nuint32_t& a)
|
||||
{
|
||||
char tmp[INET_ADDRSTRLEN] = {0};
|
||||
if(inet_ntop(AF_INET, (void*)&a.n, tmp, sizeof(tmp)))
|
||||
{
|
||||
out << tmp;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
struct Hash
|
||||
{
|
||||
inline size_t
|
||||
operator ()(nuint32_t x) const
|
||||
{
|
||||
return std::hash< uint32_t >{}(x.n);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
struct huint16_t
|
||||
{
|
||||
uint16_t h;
|
||||
|
||||
constexpr huint16_t
|
||||
operator &(huint16_t x) const { return huint16_t{uint16_t(h & x.h)}; }
|
||||
constexpr huint16_t
|
||||
operator |(huint16_t x) const { return huint16_t{uint16_t(h | x.h)}; }
|
||||
constexpr huint16_t
|
||||
operator ~() const { return huint16_t{uint16_t(~h)}; }
|
||||
|
||||
inline huint16_t operator ++() { ++h; return *this; }
|
||||
inline huint16_t operator --() { --h; return *this; }
|
||||
|
||||
constexpr bool operator <(huint16_t x) const { return h < x.h; }
|
||||
constexpr bool operator ==(huint16_t x) const { return h == x.h; }
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& out, const huint16_t& a)
|
||||
{
|
||||
return out << a.h;
|
||||
}
|
||||
|
||||
struct Hash
|
||||
{
|
||||
inline size_t
|
||||
operator ()(huint16_t x) const
|
||||
{
|
||||
return std::hash< uint16_t >{}(x.h);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
struct nuint16_t
|
||||
{
|
||||
uint16_t n;
|
||||
|
||||
constexpr nuint16_t
|
||||
operator &(nuint16_t x) const { return nuint16_t{uint16_t(n & x.n)}; }
|
||||
constexpr nuint16_t
|
||||
operator |(nuint16_t x) const { return nuint16_t{uint16_t(n | x.n)}; }
|
||||
constexpr nuint16_t
|
||||
operator ~() const { return nuint16_t{uint16_t(~n)}; }
|
||||
|
||||
inline nuint16_t operator ++() { ++n; return *this; }
|
||||
inline nuint16_t operator --() { --n; return *this; }
|
||||
|
||||
constexpr bool operator <(nuint16_t x) const { return n < x.n; }
|
||||
constexpr bool operator ==(nuint16_t x) const { return n == x.n; }
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& out, const nuint16_t& a)
|
||||
{
|
||||
return out << ntohs(a.n);
|
||||
}
|
||||
|
||||
struct Hash
|
||||
{
|
||||
inline size_t
|
||||
operator ()(nuint16_t x) const
|
||||
{
|
||||
return std::hash< uint16_t >{}(x.n);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
|
||||
static inline nuint32_t
|
||||
xhtonl(huint32_t x)
|
||||
{
|
||||
return nuint32_t{htonl(x.h)};
|
||||
}
|
||||
|
||||
static inline huint32_t
|
||||
xntohl(nuint32_t x)
|
||||
{
|
||||
return huint32_t{ntohl(x.n)};
|
||||
}
|
||||
|
||||
static inline nuint16_t
|
||||
xhtons(huint16_t x)
|
||||
{
|
||||
return nuint16_t{htons(x.h)};
|
||||
}
|
||||
|
||||
static inline huint16_t
|
||||
xntohs(nuint16_t x)
|
||||
{
|
||||
return huint16_t{ntohs(x.n)};
|
||||
}
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -0,0 +1,211 @@
|
||||
#include <llarp/dns/message.hpp>
|
||||
#include <llarp/endian.hpp>
|
||||
#include <llarp/logger.hpp>
|
||||
#include <llarp/buffer.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dns
|
||||
{
|
||||
bool
|
||||
MessageHeader::Encode(llarp_buffer_t* buf) const
|
||||
{
|
||||
if(!llarp_buffer_put_uint16(buf, id))
|
||||
return false;
|
||||
if(!llarp_buffer_put_uint16(buf, fields))
|
||||
return false;
|
||||
if(!llarp_buffer_put_uint16(buf, qd_count))
|
||||
return false;
|
||||
if(!llarp_buffer_put_uint16(buf, an_count))
|
||||
return false;
|
||||
if(!llarp_buffer_put_uint16(buf, ns_count))
|
||||
return false;
|
||||
return llarp_buffer_put_uint16(buf, ar_count);
|
||||
}
|
||||
|
||||
bool
|
||||
MessageHeader::Decode(llarp_buffer_t* buf)
|
||||
{
|
||||
if(!llarp_buffer_read_uint16(buf, &id))
|
||||
return false;
|
||||
if(!llarp_buffer_read_uint16(buf, &fields))
|
||||
return false;
|
||||
if(!llarp_buffer_read_uint16(buf, &qd_count))
|
||||
return false;
|
||||
if(!llarp_buffer_read_uint16(buf, &an_count))
|
||||
return false;
|
||||
if(!llarp_buffer_read_uint16(buf, &ns_count))
|
||||
return false;
|
||||
return llarp_buffer_read_uint16(buf, &ar_count);
|
||||
}
|
||||
|
||||
Message::Message(Message&& other)
|
||||
: hdr_id(std::move(other.hdr_id))
|
||||
, hdr_fields(std::move(other.hdr_fields))
|
||||
, questions(std::move(other.questions))
|
||||
, answers(std::move(other.answers))
|
||||
, authorities(std::move(other.authorities))
|
||||
, additional(std::move(other.additional))
|
||||
{
|
||||
}
|
||||
|
||||
Message::Message(const Message& other)
|
||||
: hdr_id(other.hdr_id)
|
||||
, hdr_fields(other.hdr_fields)
|
||||
, questions(other.questions)
|
||||
, answers(other.answers)
|
||||
, authorities(other.authorities)
|
||||
, additional(other.additional)
|
||||
{
|
||||
}
|
||||
|
||||
Message::Message(const MessageHeader& hdr)
|
||||
: hdr_id(hdr.id)
|
||||
, hdr_fields(hdr.fields)
|
||||
, questions(size_t(hdr.qd_count))
|
||||
, answers(size_t(hdr.an_count))
|
||||
, authorities(size_t(hdr.ns_count))
|
||||
, additional(size_t(hdr.ar_count))
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Message::Encode(llarp_buffer_t* buf) const
|
||||
{
|
||||
MessageHeader hdr;
|
||||
hdr.id = hdr_id;
|
||||
hdr.fields = hdr_fields;
|
||||
hdr.qd_count = questions.size();
|
||||
hdr.an_count = answers.size();
|
||||
hdr.ns_count = authorities.size();
|
||||
hdr.ar_count = additional.size();
|
||||
|
||||
if(!hdr.Encode(buf))
|
||||
return false;
|
||||
|
||||
for(const auto& question : questions)
|
||||
if(!question.Encode(buf))
|
||||
return false;
|
||||
|
||||
for(const auto& answer : answers)
|
||||
if(!answer.Encode(buf))
|
||||
return false;
|
||||
|
||||
for(const auto& auth : authorities)
|
||||
if(!auth.Encode(buf))
|
||||
return false;
|
||||
|
||||
for(const auto& rr : additional)
|
||||
if(!rr.Encode(buf))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Message::Decode(llarp_buffer_t* buf)
|
||||
{
|
||||
for(auto& qd : questions)
|
||||
{
|
||||
if(!qd.Decode(buf))
|
||||
{
|
||||
llarp::LogError("failed to decode question");
|
||||
return false;
|
||||
}
|
||||
llarp::LogDebug(qd);
|
||||
}
|
||||
|
||||
for(auto& an : answers)
|
||||
{
|
||||
if(!an.Decode(buf))
|
||||
{
|
||||
llarp::LogError("failed to decode answer");
|
||||
return false;
|
||||
}
|
||||
llarp::LogDebug(an);
|
||||
}
|
||||
|
||||
for(auto& ns : authorities)
|
||||
{
|
||||
if(!ns.Decode(buf))
|
||||
{
|
||||
llarp::LogError("failed to decode authority");
|
||||
return false;
|
||||
}
|
||||
llarp::LogDebug(ns);
|
||||
}
|
||||
|
||||
for(auto& ar : additional)
|
||||
{
|
||||
if(!ar.Decode(buf))
|
||||
{
|
||||
llarp::LogError("failed to decode additonal");
|
||||
return false;
|
||||
}
|
||||
llarp::LogDebug(ar);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Message::AddINReply(llarp::huint32_t ip)
|
||||
{
|
||||
if(questions.size())
|
||||
{
|
||||
hdr_fields |= (1 << 15);
|
||||
const auto& question = questions[0];
|
||||
ResourceRecord rec;
|
||||
rec.rr_name = question.qname;
|
||||
rec.rr_type = 1;
|
||||
rec.rr_class = 1;
|
||||
rec.ttl = 1;
|
||||
rec.rData.resize(4);
|
||||
htobe32buf(rec.rData.data(), ip.h);
|
||||
answers.emplace_back(std::move(rec));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Message::AddAReply(std::string name)
|
||||
{
|
||||
if(questions.size())
|
||||
{
|
||||
hdr_fields |= (1 << 15);
|
||||
const auto& question = questions[0];
|
||||
answers.emplace_back();
|
||||
auto& rec = answers.back();
|
||||
rec.rr_name = question.qname;
|
||||
rec.rr_type = question.qtype;
|
||||
rec.rr_class = 1;
|
||||
rec.ttl = 1;
|
||||
byte_t tmp[512] = {0};
|
||||
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
|
||||
if(EncodeName(&buf, name))
|
||||
{
|
||||
buf.sz = buf.cur - buf.base;
|
||||
rec.rData.resize(buf.sz);
|
||||
memcpy(rec.rData.data(), buf.base, buf.sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Message::AddNXReply()
|
||||
{
|
||||
if(questions.size())
|
||||
{
|
||||
hdr_fields |= (1 << 15) | (1 << 3);
|
||||
const auto& question = questions[0];
|
||||
answers.emplace_back();
|
||||
auto& nx = answers.back();
|
||||
nx.rr_name = question.qname;
|
||||
nx.rr_type = question.qtype;
|
||||
nx.rr_class = question.qclass;
|
||||
nx.ttl = 1;
|
||||
nx.rData.resize(1);
|
||||
nx.rData.data()[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
@ -0,0 +1,102 @@
|
||||
#include <llarp/dns/name.hpp>
|
||||
#include <llarp/net.hpp>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dns
|
||||
{
|
||||
bool
|
||||
DecodeName(llarp_buffer_t* buf, Name_t& name)
|
||||
{
|
||||
if(llarp_buffer_size_left(*buf) < 1)
|
||||
return false;
|
||||
std::stringstream ss;
|
||||
size_t l;
|
||||
do
|
||||
{
|
||||
l = *buf->cur;
|
||||
buf->cur++;
|
||||
if(l)
|
||||
{
|
||||
if(l > 63)
|
||||
{
|
||||
llarp::LogError("decode name failed, field too big: ", l, " > 63");
|
||||
llarp::DumpBuffer(*buf);
|
||||
return false;
|
||||
}
|
||||
if(llarp_buffer_size_left(*buf) < l)
|
||||
return false;
|
||||
|
||||
ss << Name_t((const char*)buf->cur, l);
|
||||
ss << ".";
|
||||
}
|
||||
buf->cur = buf->cur + l;
|
||||
} while(l);
|
||||
name = ss.str();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
EncodeName(llarp_buffer_t* buf, const Name_t& name)
|
||||
{
|
||||
std::stringstream ss;
|
||||
if(name.size() && name[name.size() - 1] == '.')
|
||||
ss << name.substr(0, name.size() - 1);
|
||||
else
|
||||
ss << name;
|
||||
|
||||
std::string part;
|
||||
while(std::getline(ss, part, '.'))
|
||||
{
|
||||
size_t l = part.length();
|
||||
if(l > 63)
|
||||
return false;
|
||||
*(buf->cur) = l;
|
||||
buf->cur++;
|
||||
if(llarp_buffer_size_left(*buf) < l)
|
||||
return false;
|
||||
if(l)
|
||||
{
|
||||
memcpy(buf->cur, part.data(), l);
|
||||
buf->cur += l;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
*buf->cur = 0;
|
||||
buf->cur++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DecodePTR(const Name_t& name, huint32_t& ip)
|
||||
{
|
||||
auto pos = name.find(".in-addr.arpa");
|
||||
if(pos == std::string::npos)
|
||||
return false;
|
||||
std::string sub = name.substr(0, pos + 1);
|
||||
if(std::count(sub.begin(), sub.end(), '.') == 4)
|
||||
{
|
||||
uint8_t a, b, c, d;
|
||||
pos = sub.find('.');
|
||||
d = atoi(sub.substr(0, pos).c_str());
|
||||
sub = sub.substr(pos + 1);
|
||||
pos = sub.find('.');
|
||||
c = atoi(sub.substr(0, pos).c_str());
|
||||
sub = sub.substr(pos + 1);
|
||||
pos = sub.find('.');
|
||||
b = atoi(sub.substr(0, pos).c_str());
|
||||
sub = sub.substr(pos + 1);
|
||||
pos = sub.find('.');
|
||||
a = atoi(sub.substr(0, pos).c_str());
|
||||
ip = llarp::ipaddr_ipv4_bits(a, b, c, d);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
@ -0,0 +1,50 @@
|
||||
#include <llarp/dns/question.hpp>
|
||||
#include <llarp/logger.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dns
|
||||
{
|
||||
Question::Question(Question&& other)
|
||||
: qname(std::move(other.qname))
|
||||
, qtype(std::move(other.qtype))
|
||||
, qclass(std::move(other.qclass))
|
||||
{
|
||||
}
|
||||
Question::Question(const Question& other)
|
||||
: qname(other.qname), qtype(other.qtype), qclass(other.qclass)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Question::Encode(llarp_buffer_t* buf) const
|
||||
{
|
||||
if(!EncodeName(buf, qname))
|
||||
return false;
|
||||
if(!llarp_buffer_put_uint16(buf, qtype))
|
||||
return false;
|
||||
return llarp_buffer_put_uint16(buf, qclass);
|
||||
}
|
||||
|
||||
bool
|
||||
Question::Decode(llarp_buffer_t* buf)
|
||||
{
|
||||
if(!DecodeName(buf, qname))
|
||||
{
|
||||
llarp::LogError("failed to decode name");
|
||||
return false;
|
||||
}
|
||||
if(!llarp_buffer_read_uint16(buf, &qtype))
|
||||
{
|
||||
llarp::LogError("failed to decode type");
|
||||
return false;
|
||||
}
|
||||
if(!llarp_buffer_read_uint16(buf, &qclass))
|
||||
{
|
||||
llarp::LogError("failed to decode class");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
@ -0,0 +1,83 @@
|
||||
#include <llarp/dns/rr.hpp>
|
||||
#include <llarp/logger.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dns
|
||||
{
|
||||
ResourceRecord::ResourceRecord(const ResourceRecord& other)
|
||||
: rr_name(other.rr_name)
|
||||
, rr_type(other.rr_type)
|
||||
, rr_class(other.rr_class)
|
||||
, ttl(other.ttl)
|
||||
, rData(other.rData)
|
||||
{
|
||||
}
|
||||
|
||||
ResourceRecord::ResourceRecord(ResourceRecord&& other)
|
||||
: rr_name(std::move(other.rr_name))
|
||||
, rr_type(std::move(other.rr_type))
|
||||
, rr_class(std::move(other.rr_class))
|
||||
, ttl(std::move(other.ttl))
|
||||
, rData(std::move(other.rData))
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
ResourceRecord::Encode(llarp_buffer_t* buf) const
|
||||
{
|
||||
if(!EncodeName(buf, rr_name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!llarp_buffer_put_uint16(buf, rr_type))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!llarp_buffer_put_uint16(buf, rr_class))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!llarp_buffer_put_uint32(buf, ttl))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!EncodeRData(buf, rData))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ResourceRecord::Decode(llarp_buffer_t* buf)
|
||||
{
|
||||
if(!DecodeName(buf, rr_name))
|
||||
{
|
||||
llarp::LogError("failed to decode rr name");
|
||||
return false;
|
||||
}
|
||||
if(!llarp_buffer_read_uint16(buf, &rr_type))
|
||||
{
|
||||
llarp::LogError("failed to decode rr type");
|
||||
return false;
|
||||
}
|
||||
if(!llarp_buffer_read_uint16(buf, &rr_class))
|
||||
{
|
||||
llarp::LogError("failed to decode rr class");
|
||||
return false;
|
||||
}
|
||||
if(!llarp_buffer_read_uint32(buf, &ttl))
|
||||
{
|
||||
llarp::LogError("failed to decode ttl");
|
||||
return false;
|
||||
}
|
||||
if(!DecodeRData(buf, rData))
|
||||
{
|
||||
llarp::LogError("failed to decode rr rdata");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
@ -0,0 +1,42 @@
|
||||
#include <llarp/dns/serialize.hpp>
|
||||
#include <llarp/net_int.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dns
|
||||
{
|
||||
bool
|
||||
EncodeRData(llarp_buffer_t* buf, const std::vector< byte_t >& v)
|
||||
{
|
||||
if(v.size() > 65536)
|
||||
return false;
|
||||
uint16_t len = v.size();
|
||||
if(!llarp_buffer_put_uint16(buf, len))
|
||||
return false;
|
||||
if(llarp_buffer_size_left(*buf) < len)
|
||||
return false;
|
||||
memcpy(buf->cur, v.data(), len);
|
||||
buf->cur += len;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DecodeRData(llarp_buffer_t* buf, std::vector< byte_t >& v)
|
||||
{
|
||||
uint16_t len;
|
||||
if(!llarp_buffer_read_uint16(buf, &len))
|
||||
return false;
|
||||
size_t left = llarp_buffer_size_left(*buf);
|
||||
if(left < len)
|
||||
return false;
|
||||
v.resize(size_t(len));
|
||||
if(len)
|
||||
{
|
||||
memcpy(v.data(), buf->cur, len);
|
||||
buf->cur += len;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
@ -0,0 +1,158 @@
|
||||
#include <llarp/dns/server.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dns
|
||||
{
|
||||
Proxy::Proxy(llarp_ev_loop* loop, IQueryHandler* h)
|
||||
: m_Loop(loop), m_QueryHandler(h)
|
||||
{
|
||||
m_Client.user = this;
|
||||
m_Server.user = this;
|
||||
m_Client.tick = nullptr;
|
||||
m_Server.tick = nullptr;
|
||||
m_Client.recvfrom = &HandleUDPRecv_client;
|
||||
m_Server.recvfrom = &HandleUDPRecv_server;
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::Stop()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Proxy::Start(const llarp::Addr& addr,
|
||||
const std::vector< llarp::Addr >& resolvers)
|
||||
{
|
||||
m_Resolvers.clear();
|
||||
m_Resolvers = resolvers;
|
||||
if(m_Resolvers.size() == 0)
|
||||
{
|
||||
llarp::LogError("no upstream dns provide specified");
|
||||
return false;
|
||||
}
|
||||
llarp::Addr any("0.0.0.0", 0);
|
||||
return llarp_ev_add_udp(m_Loop, &m_Server, addr) == 0
|
||||
&& llarp_ev_add_udp(m_Loop, &m_Client, any) == 0;
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::HandleUDPRecv_server(llarp_udp_io* u, const sockaddr* from,
|
||||
llarp_buffer_t buf)
|
||||
{
|
||||
static_cast< Proxy* >(u->user)->HandlePktServer(*from, &buf);
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::HandleUDPRecv_client(llarp_udp_io* u, const sockaddr* from,
|
||||
llarp_buffer_t buf)
|
||||
{
|
||||
static_cast< Proxy* >(u->user)->HandlePktClient(*from, &buf);
|
||||
}
|
||||
|
||||
llarp::Addr
|
||||
Proxy::PickRandomResolver() const
|
||||
{
|
||||
size_t sz = m_Resolvers.size();
|
||||
if(sz == 0)
|
||||
return llarp::Addr("1.1.1.1", 53);
|
||||
if(sz == 1)
|
||||
return m_Resolvers[0];
|
||||
auto itr = m_Resolvers.begin();
|
||||
std::advance(itr, llarp_randint() % sz);
|
||||
return *itr;
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::HandleTick(llarp_udp_io*)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::SendMessageTo(llarp::Addr to, Message msg)
|
||||
{
|
||||
byte_t tmp[1500] = {0};
|
||||
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
|
||||
if(msg.Encode(&buf))
|
||||
{
|
||||
buf.sz = buf.cur - buf.base;
|
||||
buf.cur = buf.base;
|
||||
llarp_ev_udp_sendto(&m_Server, to, buf);
|
||||
}
|
||||
else
|
||||
llarp::LogWarn("failed to encode dns message when sending");
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::HandlePktClient(llarp::Addr from, llarp_buffer_t* pkt)
|
||||
{
|
||||
MessageHeader hdr;
|
||||
if(!hdr.Decode(pkt))
|
||||
{
|
||||
llarp::LogWarn("failed to parse dns header from ", from);
|
||||
return;
|
||||
}
|
||||
TX tx = {hdr.id, from};
|
||||
auto itr = m_Forwarded.find(tx);
|
||||
if(itr != m_Forwarded.end())
|
||||
{
|
||||
llarp_buffer_t buf;
|
||||
buf.sz = pkt->sz;
|
||||
buf.base = pkt->base;
|
||||
buf.cur = buf.base;
|
||||
// forward reply
|
||||
llarp_ev_udp_sendto(&m_Server, itr->second, buf);
|
||||
// remove pending
|
||||
m_Forwarded.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::HandlePktServer(llarp::Addr from, llarp_buffer_t* pkt)
|
||||
{
|
||||
MessageHeader hdr;
|
||||
if(!hdr.Decode(pkt))
|
||||
{
|
||||
llarp::LogWarn("failed to parse dns header from ", from);
|
||||
return;
|
||||
}
|
||||
TX tx = {hdr.id, from};
|
||||
auto itr = m_Forwarded.find(tx);
|
||||
Message msg(hdr);
|
||||
if(!msg.Decode(pkt))
|
||||
{
|
||||
llarp::LogWarn("failed to parse dns message from ", from);
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_QueryHandler && m_QueryHandler->ShouldHookDNSMessage(msg))
|
||||
{
|
||||
if(!m_QueryHandler->HandleHookedDNSMessage(
|
||||
std::move(msg),
|
||||
std::bind(&Proxy::SendMessageTo, this, from,
|
||||
std::placeholders::_1)))
|
||||
{
|
||||
llarp::LogWarn("failed to handle hooked dns");
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if(itr == m_Forwarded.end())
|
||||
{
|
||||
// new forwarded query
|
||||
tx.from = PickRandomResolver();
|
||||
m_Forwarded[tx] = from;
|
||||
llarp_buffer_t buf;
|
||||
buf.sz = pkt->sz;
|
||||
buf.base = pkt->base;
|
||||
buf.cur = buf.base;
|
||||
// do query
|
||||
llarp_ev_udp_sendto(&m_Client, tx.from, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
// drop (?)
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
@ -0,0 +1,147 @@
|
||||
#include <llarp/dns/dns.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
#include <algorithm>
|
||||
#include <llarp/net.hpp>
|
||||
|
||||
struct DNSLibTest : public ::testing::Test
|
||||
{
|
||||
byte_t mem[1500];
|
||||
llarp_buffer_t buf = llarp::StackBuffer< decltype(mem) >(mem);
|
||||
|
||||
void
|
||||
SetUp()
|
||||
{
|
||||
buf.sz = sizeof(mem);
|
||||
Rewind();
|
||||
memset(mem, '$', sizeof(mem));
|
||||
}
|
||||
|
||||
void
|
||||
Rewind()
|
||||
{
|
||||
buf.cur = buf.base;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(DNSLibTest, TestPTR)
|
||||
{
|
||||
llarp::huint32_t ip = {0};
|
||||
llarp::huint32_t expected = llarp::ipaddr_ipv4_bits(10, 10, 10, 1);
|
||||
ASSERT_TRUE(llarp::dns::DecodePTR("1.10.10.10.in-addr.arpa.", ip));
|
||||
ASSERT_EQ(ip, expected);
|
||||
};
|
||||
|
||||
TEST_F(DNSLibTest, TestSerializeHeader)
|
||||
{
|
||||
llarp::dns::MessageHeader hdr, other;
|
||||
hdr.id = 0x1234;
|
||||
hdr.fields = (1 << 15);
|
||||
hdr.qd_count = 1;
|
||||
hdr.an_count = 1;
|
||||
hdr.ns_count = 0;
|
||||
hdr.ar_count = 0;
|
||||
ASSERT_TRUE(hdr.Encode(&buf));
|
||||
ASSERT_TRUE((buf.cur - buf.base) == llarp::dns::MessageHeader::Size);
|
||||
Rewind();
|
||||
ASSERT_TRUE(other.Decode(&buf));
|
||||
ASSERT_TRUE(hdr == other);
|
||||
ASSERT_TRUE(other.id == 0x1234);
|
||||
ASSERT_TRUE(other.fields == (1 << 15));
|
||||
};
|
||||
|
||||
TEST_F(DNSLibTest, TestSerializeName)
|
||||
{
|
||||
const llarp::dns::Name_t name = "whatever.tld";
|
||||
const llarp::dns::Name_t expected = "whatever.tld.";
|
||||
llarp::dns::Name_t other;
|
||||
Rewind();
|
||||
ASSERT_TRUE(llarp::dns::EncodeName(&buf, name));
|
||||
Rewind();
|
||||
ASSERT_EQ(buf.base[0], 8);
|
||||
ASSERT_EQ(buf.base[1], 'w');
|
||||
ASSERT_EQ(buf.base[2], 'h');
|
||||
ASSERT_EQ(buf.base[3], 'a');
|
||||
ASSERT_EQ(buf.base[4], 't');
|
||||
ASSERT_EQ(buf.base[5], 'e');
|
||||
ASSERT_EQ(buf.base[6], 'v');
|
||||
ASSERT_EQ(buf.base[7], 'e');
|
||||
ASSERT_EQ(buf.base[8], 'r');
|
||||
ASSERT_EQ(buf.base[9], 3);
|
||||
ASSERT_EQ(buf.base[10], 't');
|
||||
ASSERT_EQ(buf.base[11], 'l');
|
||||
ASSERT_EQ(buf.base[12], 'd');
|
||||
ASSERT_EQ(buf.base[13], 0);
|
||||
ASSERT_TRUE(llarp::dns::DecodeName(&buf, other));
|
||||
ASSERT_EQ(expected, other);
|
||||
};
|
||||
|
||||
TEST_F(DNSLibTest, TestSerializeQuestion)
|
||||
{
|
||||
const std::string name = "whatever.tld";
|
||||
const std::string expected_name = name + ".";
|
||||
llarp::dns::Question q, other;
|
||||
q.qname = name;
|
||||
q.qclass = 1;
|
||||
q.qtype = 1;
|
||||
ASSERT_TRUE(q.Encode(&buf));
|
||||
Rewind();
|
||||
ASSERT_TRUE(other.Decode(&buf));
|
||||
ASSERT_EQ(other.qname, expected_name);
|
||||
ASSERT_EQ(q.qclass, other.qclass);
|
||||
ASSERT_EQ(q.qtype, other.qtype);
|
||||
};
|
||||
|
||||
TEST_F(DNSLibTest, TestSerializeMessage)
|
||||
{
|
||||
llarp::dns::Question expected_question;
|
||||
expected_question.qname = "whatever.tld.";
|
||||
expected_question.qclass = 1;
|
||||
expected_question.qtype = 1;
|
||||
llarp::dns::MessageHeader hdr, otherHdr;
|
||||
hdr.id = 0xfeed;
|
||||
hdr.fields = (1 << 15);
|
||||
hdr.qd_count = 1;
|
||||
hdr.an_count = 0;
|
||||
hdr.ns_count = 0;
|
||||
hdr.ar_count = 0;
|
||||
llarp::dns::Message m(hdr);
|
||||
m.hdr_id = 0x1234;
|
||||
m.hdr_fields = (1 << 15);
|
||||
auto& q = m.questions[0];
|
||||
q.qname = "whatever.tld";
|
||||
q.qclass = 1;
|
||||
q.qtype = 1;
|
||||
m.AddINReply({1});
|
||||
ASSERT_EQ(m.questions.size(), 1U);
|
||||
ASSERT_EQ(m.answers.size(), 1U);
|
||||
ASSERT_TRUE(m.Encode(&buf));
|
||||
|
||||
Rewind();
|
||||
|
||||
ASSERT_TRUE(otherHdr.Decode(&buf));
|
||||
llarp::dns::Message other(otherHdr);
|
||||
ASSERT_TRUE(buf.cur - buf.base == llarp::dns::MessageHeader::Size);
|
||||
ASSERT_TRUE(other.Decode(&buf));
|
||||
ASSERT_EQ(other.questions.size(), 1U);
|
||||
ASSERT_EQ(expected_question.qname, other.questions[0].qname);
|
||||
ASSERT_EQ(expected_question.qclass, other.questions[0].qclass);
|
||||
ASSERT_EQ(expected_question.qtype, other.questions[0].qtype);
|
||||
ASSERT_TRUE(expected_question == other.questions[0]);
|
||||
ASSERT_EQ(other.answers.size(), 1U);
|
||||
ASSERT_EQ(other.answers[0].rData.size(), 4U);
|
||||
};
|
||||
|
||||
TEST_F(DNSLibTest, TestEncodeDecode_RData)
|
||||
{
|
||||
static constexpr size_t rdatasize = 32;
|
||||
llarp::dns::RR_RData_t rdata(rdatasize);
|
||||
std::fill(rdata.begin(), rdata.end(), 'a');
|
||||
|
||||
llarp::dns::RR_RData_t other_rdata;
|
||||
|
||||
ASSERT_TRUE(llarp::dns::EncodeRData(&buf, rdata));
|
||||
ASSERT_TRUE(buf.cur - buf.base == rdatasize + sizeof(uint16_t));
|
||||
Rewind();
|
||||
ASSERT_TRUE(llarp::dns::DecodeRData(&buf, other_rdata));
|
||||
ASSERT_TRUE(rdata == other_rdata);
|
||||
};
|
Loading…
Reference in New Issue