1 #include "DNS-ldns.hpp"
3 #include "DNS-iostream.hpp"
8 #include <cstdbool> // needs to be above ldns includes
10 #include <ldns/packet.h>
13 #include <arpa/inet.h>
15 #include <glog/logging.h>
17 #include <fmt/format.h>
21 std::string
rr_name_str(ldns_rdf
const* rdf
)
23 auto const sz
= ldns_rdf_size(rdf
);
25 if (sz
> LDNS_MAX_DOMAINLEN
) {
26 LOG(WARNING
) << "rdf size too large";
30 return ""; // root label
33 auto const data
= ldns_rdf_data(rdf
);
35 unsigned char src_pos
= 0;
36 unsigned char len
= data
[src_pos
];
40 while ((len
> 0) && (src_pos
< sz
)) {
42 for (unsigned char i
= 0; i
< len
; ++i
) {
43 unsigned char c
= data
[src_pos
];
44 // if (c == '.' || c == ';' || c == '(' || c == ')' || c == '\\') {
45 if (c
== '.' || c
== '\\') {
49 // else if (!(isascii(c) && isgraph(c))) {
50 // str += fmt::format("0x{:02x}", c);
63 if (str
.length() && ('.' == str
.back())) {
64 str
.erase(str
.length() - 1);
70 std::string
rr_str(ldns_rdf
const* rdf
)
74 auto const data
= static_cast<char const*>(rdf
->_data
);
75 auto const udata
= static_cast<unsigned char const*>(rdf
->_data
);
77 return std::string(data
+ 1, static_cast<std::string::size_type
>(*udata
));
82 auto const status
= ldns_resolver_new_frm_file(&res_
, nullptr);
83 CHECK_EQ(status
, LDNS_STATUS_OK
) << "failed to initialize DNS resolver: "
84 << ldns_get_errorstr_by_id(status
);
87 Resolver::~Resolver() { ldns_resolver_deep_free(res_
); }
89 Domain::Domain(char const* domain
)
91 , rdfp_(CHECK_NOTNULL(ldns_dname_new_frm_str(domain
)))
95 Domain::Domain(std::string
const& domain
)
97 , rdfp_(CHECK_NOTNULL(ldns_dname_new_frm_str(domain
.c_str())))
101 Domain::~Domain() { ldns_rdf_deep_free(rdfp_
); }
103 Query::Query(Resolver
const& res
, DNS::RR_type type
, std::string
const& dom
)
104 : Query(res
, type
, dom
.c_str())
108 Query::Query(Resolver
const& res
, DNS::RR_type type
, char const* domain
)
110 Domain
const dom
{domain
};
112 ldns_status
const status
= ldns_resolver_query_status(
113 &p_
, res
.get(), dom
.get(), static_cast<ldns_enum_rr_type
>(type
),
114 LDNS_RR_CLASS_IN
, LDNS_RD
| LDNS_AD
);
116 if (status
!= LDNS_STATUS_OK
) {
117 bogus_or_indeterminate_
= true;
119 // LOG(WARNING) << "Query (" << dom.str() << "/" << type << ") "
120 // << "ldns_resolver_query_status failed: "
121 // << ldns_get_errorstr_by_id(status);
123 // If we have only one nameserver, reset the RTT otherwise all
124 // future use of this resolver object will fail.
126 ldns_resolver_set_nameserver_rtt(res
.get(), 0,
127 LDNS_RESOLV_RTT_MIN
); // "reachable"
131 authentic_data_
= ldns_pkt_ad(p_
);
133 truncation_
= ldns_pkt_tc(p_
);
135 // if UDP, retry with TCP?
136 bogus_or_indeterminate_
= true;
137 LOG(WARNING
) << "truncated answer (" << dom
.str() << "/" << type
<< ")";
140 auto const rcode
= ldns_pkt_get_rcode(p_
);
142 case LDNS_RCODE_NOERROR
: break;
144 case LDNS_RCODE_NXDOMAIN
:
146 // LOG(WARNING) << "NX domain (" << dom.str() << "/" << type << ")";
149 case LDNS_RCODE_SERVFAIL
:
150 bogus_or_indeterminate_
= true;
151 // LOG(WARNING) << "DNS server fail (" << dom.str() << "/" << type << ")";
155 bogus_or_indeterminate_
= true;
156 LOG(WARNING
) << "DNS unknown error (" << dom
.str() << "/" << type
157 << "), rcode = " << DNS::rcode_c_str(rcode
) << " (" << rcode
170 DNS::RR_collection
Query::get_records() const
172 RR_list
const rrlst
{*this};
173 return rrlst
.get_records();
176 std::vector
<std::string
> Query::get_strings() const
178 RR_list
const rrlst
{*this};
179 return rrlst
.get_strings();
182 RR_list::RR_list(Query
const& q
)
185 // no clones, so no frees required
186 rrlst_answer_
= ldns_pkt_answer(q
.get());
187 rrlst_additional_
= ldns_pkt_additional(q
.get());
191 RR_list::~RR_list() {}
193 DNS::RR_collection
RR_list::get_records() const
195 DNS::RR_collection ret
;
199 ret
.reserve(ldns_rr_list_rr_count(rrlst_answer_
));
201 for (unsigned i
= 0; i
< ldns_rr_list_rr_count(rrlst_answer_
); ++i
) {
202 auto const rr
= ldns_rr_list_rr(rrlst_answer_
, i
);
205 // LOG(INFO) << "ldns_rr_rd_count(rr) == " << ldns_rr_rd_count(rr);
207 switch (ldns_rr_get_type(rr
)) {
208 case LDNS_RR_TYPE_A
: {
209 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
210 auto const rdf
= ldns_rr_rdf(rr
, 0);
211 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_A
);
212 ret
.emplace_back(DNS::RR_A
{ldns_rdf_data(rdf
), ldns_rdf_size(rdf
)});
215 case LDNS_RR_TYPE_CNAME
: {
216 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
217 auto const rdf
= ldns_rr_rdf(rr
, 0);
218 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_DNAME
);
219 ret
.emplace_back(DNS::RR_CNAME
{rr_name_str(rdf
)});
222 case LDNS_RR_TYPE_PTR
: {
223 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
224 auto const rdf
= ldns_rr_rdf(rr
, 0);
225 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_DNAME
);
226 ret
.emplace_back(DNS::RR_PTR
{rr_name_str(rdf
)});
229 case LDNS_RR_TYPE_MX
: {
230 CHECK_EQ(ldns_rr_rd_count(rr
), 2);
231 auto const rdf_0
= ldns_rr_rdf(rr
, 0);
232 CHECK_EQ(ldns_rdf_get_type(rdf_0
), LDNS_RDF_TYPE_INT16
);
233 auto const rdf_1
= ldns_rr_rdf(rr
, 1);
234 CHECK_EQ(ldns_rdf_get_type(rdf_1
), LDNS_RDF_TYPE_DNAME
);
236 DNS::RR_MX
{rr_name_str(rdf_1
), ldns_rdf2native_int16(rdf_0
)});
239 case LDNS_RR_TYPE_TXT
: {
240 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
241 auto const rdf
= ldns_rr_rdf(rr
, 0);
242 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_STR
);
243 ret
.emplace_back(DNS::RR_TXT
{rr_str(rdf
)});
246 case LDNS_RR_TYPE_AAAA
: {
247 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
248 auto const rdf
= ldns_rr_rdf(rr
, 0);
249 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_AAAA
);
251 DNS::RR_AAAA
{ldns_rdf_data(rdf
), ldns_rdf_size(rdf
)});
254 case LDNS_RR_TYPE_TLSA
: {
255 CHECK_EQ(ldns_rr_rd_count(rr
), 4);
257 auto const usage
{[&] {
258 auto const rdf
= ldns_rr_rdf(rr
, 0);
259 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_CERTIFICATE_USAGE
);
260 return ldns_rdf2native_int8(rdf
);
263 auto const selector
{[&] {
264 auto const rdf
= ldns_rr_rdf(rr
, 1);
265 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_SELECTOR
);
266 return ldns_rdf2native_int8(rdf
);
269 auto const matching_type
{[&] {
270 auto const rdf
= ldns_rr_rdf(rr
, 2);
271 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_MATCHING_TYPE
);
272 return ldns_rdf2native_int8(rdf
);
275 auto const rdf
= ldns_rr_rdf(rr
, 3);
276 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_HEX
);
278 ret
.emplace_back(DNS::RR_TLSA
{usage
, selector
, matching_type
,
280 ldns_rdf_size(rdf
)});
285 LOG(WARNING
) << "unknown RR type == " << ldns_rr_get_type(rr
);
292 if (rrlst_additional_
) {
293 auto const rr_count
= ldns_rr_list_rr_count(rrlst_additional_
);
295 LOG(WARNING
) << rr_count
<< " additional RR records";
296 for (unsigned i
= 0; i
< rr_count
; ++i
) {
297 auto const rr
= ldns_rr_list_rr(rrlst_additional_
, i
);
299 auto type
= ldns_rr_get_type(rr
);
300 LOG(WARNING
) << "additional record " << i
<< " type "
301 << DNS::RR_type_c_str(type
);
310 std::vector
<std::string
> RR_list::get_strings() const
312 std::vector
<std::string
> ret
;
316 ret
.reserve(ldns_rr_list_rr_count(rrlst_answer_
));
318 for (unsigned i
= 0; i
< ldns_rr_list_rr_count(rrlst_answer_
); ++i
) {
319 auto const rr
= ldns_rr_list_rr(rrlst_answer_
, i
);
322 // LOG(INFO) << "ldns_rr_rd_count(rr) == " << ldns_rr_rd_count(rr);
324 switch (ldns_rr_get_type(rr
)) {
325 case LDNS_RR_TYPE_A
: {
326 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
327 auto const rdf
= ldns_rr_rdf(rr
, 0);
328 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_A
);
329 auto const a
{DNS::RR_A
{ldns_rdf_data(rdf
), ldns_rdf_size(rdf
)}};
330 ret
.emplace_back(a
.c_str());
333 case LDNS_RR_TYPE_CNAME
: {
334 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
335 auto const rdf
= ldns_rr_rdf(rr
, 0);
336 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_DNAME
);
337 ret
.emplace_back(rr_name_str(rdf
));
340 case LDNS_RR_TYPE_PTR
: {
341 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
342 auto const rdf
= ldns_rr_rdf(rr
, 0);
343 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_DNAME
);
344 ret
.emplace_back(rr_name_str(rdf
));
347 case LDNS_RR_TYPE_MX
: {
348 CHECK_EQ(ldns_rr_rd_count(rr
), 2);
349 auto const rdf_0
= ldns_rr_rdf(rr
, 0);
350 CHECK_EQ(ldns_rdf_get_type(rdf_0
), LDNS_RDF_TYPE_INT16
);
351 auto const rdf_1
= ldns_rr_rdf(rr
, 1);
352 CHECK_EQ(ldns_rdf_get_type(rdf_1
), LDNS_RDF_TYPE_DNAME
);
353 ret
.emplace_back(rr_name_str(rdf_1
));
356 case LDNS_RR_TYPE_TXT
: {
357 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
358 auto const rdf
= ldns_rr_rdf(rr
, 0);
359 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_STR
);
360 ret
.emplace_back(rr_str(rdf
));
363 case LDNS_RR_TYPE_AAAA
: {
364 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
365 auto const rdf
= ldns_rr_rdf(rr
, 0);
366 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_AAAA
);
367 auto const a
{DNS::RR_AAAA
{ldns_rdf_data(rdf
), ldns_rdf_size(rdf
)}};
368 ret
.emplace_back(a
.c_str());
372 LOG(WARNING
) << "unknown RR type == " << ldns_rr_get_type(rr
);
382 DNS::RR_collection
Resolver::get_records(DNS::RR_type typ
,
383 char const* domain
) const
385 Query
const q
{*this, typ
, domain
};
386 RR_list
const rrlst
{q
};
387 return rrlst
.get_records();
390 std::vector
<std::string
> Resolver::get_strings(DNS::RR_type typ
,
391 char const* domain
) const
393 Query
const q
{*this, typ
, domain
};
394 RR_list
const rrlst
{q
};
395 return rrlst
.get_strings();
398 } // namespace DNS_ldns