]>
Commit | Line | Data |
---|---|---|
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 | ||
21 | class DNSName | |
22 | { | |
23 | public: | |
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 | 44 | private: |
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 | 50 | inline 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 */ | |
59 | struct 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 | }; |