]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsname.cc
2 #include <boost/format.hpp>
5 #include "dnswriter.hh"
8 #include <boost/functional/hash.hpp>
11 in DNS label format, with trailing 0. W/o trailing 0, we are 'empty'
12 www.powerdns.com = 3www8powerdns3com0
15 std::ostream
& operator<<(std::ostream
&os
, const DNSName
& d
)
17 return os
<<d
.toString();
21 DNSName::DNSName(const char* p
)
23 if(p
[0]==0 || (p
[0]=='.' && p
[1]==0)) {
24 d_storage
.assign(1, (char)0);
26 d_storage
.reserve(strlen(p
)+1);
27 auto labels
= segmentDNSName(p
);
28 for(const auto& e
: labels
)
33 DNSName::DNSName(const char* pos
, int len
, int offset
, bool uncompress
, uint16_t* qtype
, uint16_t* qclass
, unsigned int* consumed
)
36 throw std::range_error("Trying to read past the end of the buffer");
39 if(const void * fnd
=memchr(pos
+offset
, 0, len
-offset
)) {
40 d_storage
.reserve(2+(const char*)fnd
-(pos
+offset
));
44 packetParser(pos
, len
, offset
, uncompress
, qtype
, qclass
, consumed
);
47 // this should be the __only__ dns name parser in PowerDNS.
48 void DNSName::packetParser(const char* qpos
, int len
, int offset
, bool uncompress
, uint16_t* qtype
, uint16_t* qclass
, unsigned int* consumed
, int depth
)
50 const unsigned char* pos
=(const unsigned char*)qpos
;
51 unsigned char labellen
;
52 const unsigned char *opos
= pos
;
55 throw std::range_error("Trying to read past the end of the buffer");
58 const unsigned char* end
= pos
+ len
;
59 while((labellen
=*pos
++) && pos
< end
) { // "scan and copy"
62 throw std::range_error("Found compressed label, instructed not to follow");
65 int newpos
= (labellen
<< 8) + *(const unsigned char*)pos
;
69 throw std::range_error("Abort label decompression after 100 redirects");
70 packetParser((const char*)opos
, len
, newpos
, true, 0, 0, 0, depth
);
72 throw std::range_error("Found a forward reference during label decompression");
76 if (pos
+ labellen
< end
) {
77 appendRawLabel((const char*)pos
, labellen
);
80 throw std::range_error("Found an invalid label length in qname");
84 d_storage
.append(1, (char)0); // we just parsed the root
86 *consumed
= pos
- opos
- offset
;
87 if(qtype
&& pos
+ labellen
+ 2 <= end
)
88 *qtype
=(*(const unsigned char*)pos
)*256 + *((const unsigned char*)pos
+1);
91 if(qclass
&& pos
+ labellen
+ 2 <= end
)
92 *qclass
=(*(const unsigned char*)pos
)*256 + *((const unsigned char*)pos
+1);
96 std::string
DNSName::toString(const std::string
& separator
, const bool trailing
) const
99 throw std::out_of_range("Attempt to print an unset dnsname");
103 return trailing
? separator
: "";
106 for(const auto& s
: getRawLabels()) {
107 ret
+= escapeLabel(s
) + separator
;
110 return ret
.substr(0, ret
.size()-!trailing
);
113 std::string
DNSName::toDNSString() const
116 throw std::out_of_range("Attempt to DNSString an unset dnsname");
118 return std::string(d_storage
.c_str(), d_storage
.length());
121 std::string
DNSName::toDNSStringLC() const
123 return toLower(toDNSString()); // label lengths are always < 'A'
127 * Get the length of the DNSName on the wire
129 * @return the total wirelength of the DNSName
131 size_t DNSName::wirelength() const {
132 return d_storage
.length();
135 // Are WE part of parent
136 bool DNSName::isPartOf(const DNSName
& parent
) const
138 if(parent
.empty() || empty())
139 throw std::out_of_range("empty dnsnames aren't part of anything");
141 if(parent
.d_storage
.size() > d_storage
.size())
144 // this is slightly complicated since we can't start from the end, since we can't see where a label begins/ends then
145 for(auto us
=d_storage
.cbegin(); us
<d_storage
.cend() && std::distance(us
,d_storage
.cend()) >= static_cast<unsigned int>(parent
.d_storage
.size()); us
+=*us
+1) {
146 if (std::distance(us
,d_storage
.cend()) == static_cast<unsigned int>(parent
.d_storage
.size())) {
147 auto p
= parent
.d_storage
.cbegin();
148 for(; us
!= d_storage
.cend(); ++us
, ++p
) {
149 if(dns2_tolower(*p
) != dns2_tolower(*us
))
158 DNSName
DNSName::makeRelative(const DNSName
& zone
) const
161 ret
.makeUsRelative(zone
);
162 return ret
.empty() ? zone
: ret
; // HACK FIXME400
164 void DNSName::makeUsRelative(const DNSName
& zone
)
166 if (isPartOf(zone
)) {
167 d_storage
.erase(d_storage
.size()-zone
.d_storage
.size());
168 d_storage
.append(1, (char)0); // put back the trailing 0
174 DNSName
DNSName::labelReverse() const
179 return *this; // we don't create the root automatically below
182 vector
<string
> l
=getRawLabels();
184 ret
.appendRawLabel(l
.back());
191 void DNSName::appendRawLabel(const std::string
& label
)
193 appendRawLabel(label
.c_str(), label
.length());
196 void DNSName::appendRawLabel(const char* start
, unsigned int length
)
199 throw std::range_error("no such thing as an empty label to append");
201 throw std::range_error("label too long to append");
202 if(d_storage
.size() + length
> 254) // reserve two bytes, one for length and one for the root label
203 throw std::range_error("name too long to append");
205 if(d_storage
.empty()) {
206 d_storage
.append(1, (char)length
);
209 *d_storage
.rbegin()=(char)length
;
211 d_storage
.append(start
, length
);
212 d_storage
.append(1, (char)0);
215 void DNSName::prependRawLabel(const std::string
& label
)
218 throw std::range_error("no such thing as an empty label to prepend");
219 if(label
.size() > 63)
220 throw std::range_error("label too long to prepend");
221 if(d_storage
.size() + label
.size() > 254) // reserve two bytes, one for length and one for the root label
222 throw std::range_error("name too long to prepend");
224 if(d_storage
.empty())
225 d_storage
.append(1, (char)0);
227 string_t
prep(1, (char)label
.size());
228 prep
.append(label
.c_str(), label
.size());
229 d_storage
= prep
+d_storage
;
232 bool DNSName::slowCanonCompare(const DNSName
& rhs
) const
234 auto ours
=getRawLabels(), rhsLabels
= rhs
.getRawLabels();
235 return std::lexicographical_compare(ours
.rbegin(), ours
.rend(), rhsLabels
.rbegin(), rhsLabels
.rend(), CIStringCompare());
238 vector
<string
> DNSName::getRawLabels() const
241 ret
.reserve(countLabels());
243 for(const char* p
= d_storage
.c_str(); p
< d_storage
.c_str() + d_storage
.size() && *p
; p
+=*p
+1)
244 ret
.push_back({p
+1, (unsigned int)*p
}); // XXX FIXME
249 bool DNSName::chopOff()
251 if(d_storage
.empty() || d_storage
[0]==0)
253 d_storage
.erase(0, (unsigned int)d_storage
[0]+1);
257 bool DNSName::isWildcard() const
259 if(d_storage
.size() < 2)
261 auto p
= d_storage
.begin();
262 return (*p
== 0x01 && *++p
== '*');
265 unsigned int DNSName::countLabels() const
267 unsigned int count
=0;
268 for(const char* p
= d_storage
.c_str(); p
< d_storage
.c_str() + d_storage
.size() && *p
; p
+=*p
+1)
273 void DNSName::trimToLabels(unsigned int to
)
275 while(countLabels() > to
&& chopOff())
279 bool DNSName::operator==(const DNSName
& rhs
) const
281 if(rhs
.empty() != empty() || rhs
.d_storage
.size() != d_storage
.size())
284 auto us
= d_storage
.crbegin();
285 auto p
= rhs
.d_storage
.crbegin();
286 for(; us
!= d_storage
.crend() && p
!= rhs
.d_storage
.crend(); ++us
, ++p
) { // why does this go backward?
287 if(dns2_tolower(*p
) != dns2_tolower(*us
))
293 size_t hash_value(DNSName
const& d
)
298 string
DNSName::escapeLabel(const std::string
& label
)
301 ret
.reserve(label
.size()); // saves 15% on bulk .COM load
302 for(uint8_t p
: label
) {
307 else if(p
> 0x21 && p
< 0x7e)
308 ret
.append(1, (char)p
);
310 ret
+="\\" + (boost::format("%03d") % (unsigned int)p
).str();