hello-dns/tdns/dns-storage.cc

148 lines
3.6 KiB
C++
Raw Normal View History

2018-04-09 04:20:11 +07:00
#include "dns-storage.hh"
2018-04-13 16:02:59 +07:00
#include <iomanip>
2018-04-09 04:20:11 +07:00
using namespace std;
2018-04-16 22:09:27 +07:00
//! Makes us relative to 'root', returns false if we weren't part of root
2018-04-12 21:31:43 +07:00
bool DNSName::makeRelative(const DNSName& root)
2018-04-10 01:49:37 +07:00
{
auto us = d_name, them=root.d_name;
while(!them.empty()) {
if(us.empty())
return false;
if(us.back() == them.back()) {
us.pop_back();
them.pop_back();
}
else
return false;
}
d_name = us;
return true;
}
2018-04-16 22:09:27 +07:00
//! Append two DNSNames
2018-04-14 20:57:05 +07:00
DNSName operator+(const DNSName& a, const DNSName& b)
{
DNSName ret=a;
for(const auto& l : b.d_name)
ret.d_name.push_back(l);
return ret;
}
//! This function is plain wrong and does unescape its input
DNSName makeDNSName(const std::string& str)
{
DNSName ret;
string part;
for(const auto& c: str) {
if(c=='.') {
ret.push_back(part);
part.clear();
}
else part.append(1, c);
}
if(!part.empty())
ret.push_back(part);
return ret;
}
DNSNode::~DNSNode() = default;
2018-04-16 22:09:27 +07:00
//! The big RFC 1034-compatible find function. Will perform wildcard synth if requested
2018-04-14 05:12:53 +07:00
const DNSNode* DNSNode::find(DNSName& name, DNSName& last, bool wildcard, const DNSNode** passedZonecut, DNSName* zonecutname) const
2018-04-09 04:20:11 +07:00
{
2018-04-10 05:05:41 +07:00
if(!last.empty() && rrsets.count(DNSType::NS)) {
if(passedZonecut)
*passedZonecut=this;
if(zonecutname)
*zonecutname=last;
2018-04-09 04:20:11 +07:00
}
if(name.empty()) {
2018-04-13 20:44:11 +07:00
return this;
2018-04-09 04:20:11 +07:00
}
auto iter = children.find(name.back());
2018-04-16 22:09:27 +07:00
2018-04-09 04:20:11 +07:00
if(iter == children.end()) {
2018-04-14 05:12:53 +07:00
if(!wildcard)
return this;
2018-04-16 22:09:27 +07:00
2018-04-09 04:20:11 +07:00
iter = children.find("*");
2018-04-16 22:09:27 +07:00
if(iter == children.end()) { // also no wildcard
2018-04-09 04:20:11 +07:00
return this;
}
else {
2018-04-16 22:09:27 +07:00
// Had wildcard match, picking that, matching all labels
2018-04-10 04:04:13 +07:00
while(name.size() > 1) {
last.push_front(name.back());
name.pop_back();
}
2018-04-09 04:20:11 +07:00
}
}
2018-04-16 22:09:27 +07:00
last.push_front(name.back()); // this grows the part that we matched
name.pop_back(); // and removes same parts from name
2018-04-14 05:12:53 +07:00
return iter->second.find(name, last, wildcard, passedZonecut, zonecutname);
2018-04-09 04:20:11 +07:00
}
2018-04-16 22:09:27 +07:00
//! Idempotent way of creating/accessing the DNSName in a tree
2018-04-12 21:31:43 +07:00
DNSNode* DNSNode::add(DNSName name)
2018-04-09 04:20:11 +07:00
{
if(name.empty()) return this;
2018-04-09 04:20:11 +07:00
auto back = name.back();
name.pop_back();
2018-04-14 20:57:05 +07:00
return children[back].add(name); // will make child node if needed
2018-04-09 04:20:11 +07:00
}
2018-04-16 22:09:27 +07:00
//! Used to travel the tree, 'visitor' gets called on all nodes
2018-04-12 21:31:43 +07:00
void DNSNode::visit(std::function<void(const DNSName& name, const DNSNode*)> visitor, DNSName name) const
2018-04-09 04:20:11 +07:00
{
visitor(name, this);
for(const auto& c : children)
2018-04-12 21:31:43 +07:00
c.second.visit(visitor, DNSName{c.first}+name);
2018-04-09 04:20:11 +07:00
}
2018-04-14 20:57:05 +07:00
void DNSNode::addRRs(std::unique_ptr<RRGen>&&a)
{
2018-04-18 01:45:51 +07:00
if(a->getType() == DNSType::CNAME && rrsets.size())
throw std::runtime_error("Can't add CNAME RR to a node that already has RRs present");
else if(rrsets.count(DNSType::CNAME))
throw std::runtime_error("Can't add an RR to a node that already has a CNAME");
2018-04-14 20:57:05 +07:00
rrsets[a->getType()].add(std::move(a));
}
2018-04-16 22:09:27 +07:00
// Emit an escaped DNSLabel in 'master file' format
2018-04-12 21:31:43 +07:00
std::ostream & operator<<(std::ostream &os, const DNSLabel& d)
{
2018-04-13 16:02:59 +07:00
for(uint8_t a : d.d_s) {
if(a <= 0x20 || a >= 0x7f) { // RFC 4343
os<<'\\'<<setfill('0')<<setw(3)<<(int)a;
setfill(' '); // setw resets itself
}
else {
if((char)a =='.' || (char)a=='\\')
os<<"\\";
os<<(char)a;
}
2018-04-13 16:02:59 +07:00
}
return os;
}
2018-04-16 22:09:27 +07:00
// emit a DNSName
2018-04-12 21:31:43 +07:00
std::ostream & operator<<(std::ostream &os, const DNSName& d)
2018-04-09 04:20:11 +07:00
{
if(d.empty()) os<<'.';
else for(const auto& l : d.d_name)
2018-04-09 04:20:11 +07:00
os<<l<<".";
return os;
}
2018-04-11 17:45:26 +07:00
2018-04-16 22:09:27 +07:00
// Convenience function, turns DNSName into master file format string
std::string DNSName::toString() const
{
ostringstream str;
str << *this;
return str.str();
}