]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsname.hh
implement Marek Vavrusa's suggestion that dnsdist could be used for 'split horizon...
[thirdparty/pdns.git] / pdns / dnsname.hh
CommitLineData
3c115e0f 1#pragma once
2#include <string>
3#include <deque>
ceee6652 4#include <set>
5#include <strings.h>
3c115e0f 6
7/* Quest in life:
8 accept escaped ascii presentations of DNS names and store them "natively"
9 accept a DNS packet with an offset, and extract a DNS name from it
10 build up DNSNames with prepend and append of 'raw' unescaped labels
11
12 Be able to turn them into ASCII and "DNS name in a packet" again on request
13
14 Provide some common operators for comparison, detection of being part of another domain
15
16 NOTE: For now, everything MUST be . terminated, otherwise it is an error
17*/
18
19// As a side note, we currently store the labels in a fancy deque<>, but we could go for native format storage easily
20
21class DNSName
22{
23public:
24 DNSName() {} //!< Constructs the root name
25 DNSName(const char* p); //!< Constructs from a human formatted, escaped presentation
26 DNSName(const std::string& str) : DNSName(str.c_str()) {} //!< Constructs from a human formatted, escaped presentation
b5b1018e 27 DNSName(const char* p, int len, int offset, bool uncompress, uint16_t* qtype=0, uint16_t* qclass=0); //!< Construct from a DNS Packet, taking the first question
3c115e0f 28
29 bool isPartOf(const DNSName& rhs) const; //!< Are we part of the rhs name?
30 bool operator==(const DNSName& rhs) const; //!< DNS-native comparison (case insensitive)
31 std::string toString() const; //!< Our human-friendly, escaped, representation
32 std::string toDNSString() const; //!< Our representation in DNS native format
33 void appendRawLabel(const std::string& str); //!< Append this unescaped label
34 void prependRawLabel(const std::string& str); //!< Prepend this unescaped label
35 std::deque<std::string> getRawLabels() const; //!< Individual raw unescaped labels
36 bool chopOff(); //!< Turn www.powerdns.com. into powerdns.com., returns false for .
6dcedea6 37
38 DNSName& operator+=(const DNSName& rhs)
39 {
40 for(const auto& r : rhs.d_labels)
41 d_labels.push_back(r);
42 return *this;
43 }
3c115e0f 44private:
45 std::deque<std::string> d_labels;
46 static std::string escapeLabel(const std::string& orig);
47 static std::string unescapeLabel(const std::string& orig);
48};
ceee6652 49
6dcedea6 50inline DNSName operator+(const DNSName& lhs, const DNSName& rhs)
51{
52 DNSName ret=lhs;
53 ret += rhs;
54 return ret;
55}
ceee6652 56
57/* Quest in life: serve as a rapid block list. If you add a DNSName to a root SuffixMatchNode,
58 anything part of that domain will return 'true' in check */
59struct SuffixMatchNode
60{
61 SuffixMatchNode(const std::string& name_="", bool endNode_=false) : name(name_), endNode(endNode_)
62 {}
63 std::string name;
64 mutable bool endNode;
65 mutable std::set<SuffixMatchNode> children;
66 bool operator<(const SuffixMatchNode& rhs) const
67 {
68 return strcasecmp(name.c_str(), rhs.name.c_str()) < 0;
69 }
70
71 void add(const DNSName& name)
72 {
73 add(name.getRawLabels());
74 }
75
76 void add(std::deque<std::string> labels) const
77 {
78 if(labels.empty()) { // this allows insertion of the root
79 endNode=true;
80 }
81 else if(labels.size()==1) {
0b7d7191 82 children.insert(SuffixMatchNode(*labels.begin(), true));
ceee6652 83 }
84 else {
0b7d7191 85 auto res=children.insert(SuffixMatchNode(*labels.rbegin(), false));
ceee6652 86 labels.pop_back();
87 res.first->add(labels);
88 }
89 }
90
91 bool check(const DNSName& name) const
92 {
93 return check(name.getRawLabels());
94 }
95
96
97 bool check(std::deque<std::string> labels) const
98 {
99 if(labels.empty()) // optimization
100 return endNode;
101
0b7d7191 102 SuffixMatchNode smn(*labels.rbegin());
ceee6652 103 auto child = children.find(smn);
104 if(child == children.end())
105 return endNode;
106 labels.pop_back();
107 return child->check(labels);
108 }
109
110
111};