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 auto const rcode
= ldns_pkt_get_rcode(p_
);
136 case LDNS_RCODE_NOERROR
: break;
138 case LDNS_RCODE_NXDOMAIN
:
140 // LOG(WARNING) << "NX domain (" << dom.str() << "/" << type << ")";
143 case LDNS_RCODE_SERVFAIL
:
144 bogus_or_indeterminate_
= true;
145 // LOG(WARNING) << "DNS server fail (" << dom.str() << "/" << type << ")";
149 bogus_or_indeterminate_
= true;
150 LOG(WARNING
) << "DNS unknown error (" << dom
.str() << "/" << type
151 << "), rcode = " << DNS::rcode_c_str(rcode
) << " (" << rcode
164 DNS::RR_collection
Query::get_records() const
166 RR_list
const rrlst
{*this};
167 return rrlst
.get_records();
170 std::vector
<std::string
> Query::get_strings() const
172 RR_list
const rrlst
{*this};
173 return rrlst
.get_strings();
176 RR_list::RR_list(Query
const& q
)
179 // no clones, so no frees required
180 rrlst_answer_
= ldns_pkt_answer(q
.get());
181 rrlst_additional_
= ldns_pkt_additional(q
.get());
185 RR_list::~RR_list() {}
187 DNS::RR_collection
RR_list::get_records() const
189 DNS::RR_collection ret
;
193 ret
.reserve(ldns_rr_list_rr_count(rrlst_answer_
));
195 for (unsigned i
= 0; i
< ldns_rr_list_rr_count(rrlst_answer_
); ++i
) {
196 auto const rr
= ldns_rr_list_rr(rrlst_answer_
, i
);
199 // LOG(INFO) << "ldns_rr_rd_count(rr) == " << ldns_rr_rd_count(rr);
201 switch (ldns_rr_get_type(rr
)) {
202 case LDNS_RR_TYPE_A
: {
203 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
204 auto const rdf
= ldns_rr_rdf(rr
, 0);
205 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_A
);
206 ret
.emplace_back(DNS::RR_A
{ldns_rdf_data(rdf
), ldns_rdf_size(rdf
)});
209 case LDNS_RR_TYPE_CNAME
: {
210 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
211 auto const rdf
= ldns_rr_rdf(rr
, 0);
212 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_DNAME
);
213 ret
.emplace_back(DNS::RR_CNAME
{rr_name_str(rdf
)});
216 case LDNS_RR_TYPE_PTR
: {
217 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
218 auto const rdf
= ldns_rr_rdf(rr
, 0);
219 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_DNAME
);
220 ret
.emplace_back(DNS::RR_PTR
{rr_name_str(rdf
)});
223 case LDNS_RR_TYPE_MX
: {
224 CHECK_EQ(ldns_rr_rd_count(rr
), 2);
225 auto const rdf_0
= ldns_rr_rdf(rr
, 0);
226 CHECK_EQ(ldns_rdf_get_type(rdf_0
), LDNS_RDF_TYPE_INT16
);
227 auto const rdf_1
= ldns_rr_rdf(rr
, 1);
228 CHECK_EQ(ldns_rdf_get_type(rdf_1
), LDNS_RDF_TYPE_DNAME
);
230 DNS::RR_MX
{rr_name_str(rdf_1
), ldns_rdf2native_int16(rdf_0
)});
233 case LDNS_RR_TYPE_TXT
: {
234 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
235 auto const rdf
= ldns_rr_rdf(rr
, 0);
236 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_STR
);
237 ret
.emplace_back(DNS::RR_TXT
{rr_str(rdf
)});
240 case LDNS_RR_TYPE_AAAA
: {
241 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
242 auto const rdf
= ldns_rr_rdf(rr
, 0);
243 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_AAAA
);
245 DNS::RR_AAAA
{ldns_rdf_data(rdf
), ldns_rdf_size(rdf
)});
248 case LDNS_RR_TYPE_TLSA
: {
249 CHECK_EQ(ldns_rr_rd_count(rr
), 4);
251 auto const usage
{[&] {
252 auto const rdf
= ldns_rr_rdf(rr
, 0);
253 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_CERTIFICATE_USAGE
);
254 return ldns_rdf2native_int8(rdf
);
257 auto const selector
{[&] {
258 auto const rdf
= ldns_rr_rdf(rr
, 1);
259 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_SELECTOR
);
260 return ldns_rdf2native_int8(rdf
);
263 auto const matching_type
{[&] {
264 auto const rdf
= ldns_rr_rdf(rr
, 2);
265 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_MATCHING_TYPE
);
266 return ldns_rdf2native_int8(rdf
);
269 auto const rdf
= ldns_rr_rdf(rr
, 3);
270 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_HEX
);
272 ret
.emplace_back(DNS::RR_TLSA
{usage
, selector
, matching_type
,
274 ldns_rdf_size(rdf
)});
279 LOG(WARNING
) << "unknown RR type == " << ldns_rr_get_type(rr
);
286 if (rrlst_additional_
) {
287 auto const rr_count
= ldns_rr_list_rr_count(rrlst_additional_
);
289 LOG(WARNING
) << rr_count
<< " additional RR records";
290 for (unsigned i
= 0; i
< rr_count
; ++i
) {
291 auto const rr
= ldns_rr_list_rr(rrlst_additional_
, i
);
293 auto type
= ldns_rr_get_type(rr
);
294 LOG(WARNING
) << "additional record " << i
<< " type "
295 << DNS::RR_type_c_str(type
);
304 std::vector
<std::string
> RR_list::get_strings() const
306 std::vector
<std::string
> ret
;
310 ret
.reserve(ldns_rr_list_rr_count(rrlst_answer_
));
312 for (unsigned i
= 0; i
< ldns_rr_list_rr_count(rrlst_answer_
); ++i
) {
313 auto const rr
= ldns_rr_list_rr(rrlst_answer_
, i
);
316 // LOG(INFO) << "ldns_rr_rd_count(rr) == " << ldns_rr_rd_count(rr);
318 switch (ldns_rr_get_type(rr
)) {
319 case LDNS_RR_TYPE_A
: {
320 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
321 auto const rdf
= ldns_rr_rdf(rr
, 0);
322 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_A
);
323 auto const a
{DNS::RR_A
{ldns_rdf_data(rdf
), ldns_rdf_size(rdf
)}};
324 ret
.emplace_back(a
.c_str());
327 case LDNS_RR_TYPE_CNAME
: {
328 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
329 auto const rdf
= ldns_rr_rdf(rr
, 0);
330 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_DNAME
);
331 ret
.emplace_back(rr_name_str(rdf
));
334 case LDNS_RR_TYPE_PTR
: {
335 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
336 auto const rdf
= ldns_rr_rdf(rr
, 0);
337 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_DNAME
);
338 ret
.emplace_back(rr_name_str(rdf
));
341 case LDNS_RR_TYPE_MX
: {
342 CHECK_EQ(ldns_rr_rd_count(rr
), 2);
343 auto const rdf_0
= ldns_rr_rdf(rr
, 0);
344 CHECK_EQ(ldns_rdf_get_type(rdf_0
), LDNS_RDF_TYPE_INT16
);
345 auto const rdf_1
= ldns_rr_rdf(rr
, 1);
346 CHECK_EQ(ldns_rdf_get_type(rdf_1
), LDNS_RDF_TYPE_DNAME
);
347 ret
.emplace_back(rr_name_str(rdf_1
));
350 case LDNS_RR_TYPE_TXT
: {
351 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
352 auto const rdf
= ldns_rr_rdf(rr
, 0);
353 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_STR
);
354 ret
.emplace_back(rr_str(rdf
));
357 case LDNS_RR_TYPE_AAAA
: {
358 CHECK_EQ(ldns_rr_rd_count(rr
), 1);
359 auto const rdf
= ldns_rr_rdf(rr
, 0);
360 CHECK_EQ(ldns_rdf_get_type(rdf
), LDNS_RDF_TYPE_AAAA
);
361 auto const a
{DNS::RR_AAAA
{ldns_rdf_data(rdf
), ldns_rdf_size(rdf
)}};
362 ret
.emplace_back(a
.c_str());
366 LOG(WARNING
) << "unknown RR type == " << ldns_rr_get_type(rr
);
376 DNS::RR_collection
Resolver::get_records(DNS::RR_type typ
,
377 char const* domain
) const
379 Query
const q
{*this, typ
, domain
};
380 RR_list
const rrlst
{q
};
381 return rrlst
.get_records();
384 std::vector
<std::string
> Resolver::get_strings(DNS::RR_type typ
,
385 char const* domain
) const
387 Query
const q
{*this, typ
, domain
};
388 RR_list
const rrlst
{q
};
389 return rrlst
.get_strings();
392 } // namespace DNS_ldns