1 #include "DNS-fcrdns.hpp"
2 #include "DNS-iostream.hpp"
14 #include <experimental/iterator>
16 #include <fmt/format.h>
18 void check_dnsrbl(DNS::Resolver
& res
, char const* a
)
21 "b.barracudacentral.org",
22 "dnsbl-1.uceprotect.net",
27 auto const reversed
{IP4::reverse(a
)};
29 for (auto rbl
: rbls
) {
30 auto as
= DNS::get_strings(res
, DNS::RR_type::A
, reversed
+ rbl
);
32 if (as
.front() == "127.255.255.252") {
33 LOG(INFO
) << "Typing error in DNSBL Name";
36 if (as
.front() == "127.255.255.254") {
37 LOG(INFO
) << "Anonymous query through public resolver";
40 if (as
.front() == "127.255.255.255") {
41 LOG(INFO
) << "Excessive Number of Queries";
44 std::cout
<< a
<< " advice from " << rbl
<< '\n';
46 std::cout
<< " returned: " << aa
<< '\n';
50 std::cout
<< "not on " << rbl
<< '\n';
55 void check_uribls(DNS::Resolver
& res
, char const* dom
)
63 for (auto uribl
: uribls
) {
64 auto const lookup
= fmt::format("{}.{}", dom
, uribl
);
65 auto as
= DNS::get_strings(res
, DNS::RR_type::A
, lookup
);
67 if (as
.front() == "127.255.255.252") {
68 LOG(INFO
) << "Typing error in DNSBL Name";
71 if (as
.front() == "127.255.255.254") {
72 LOG(INFO
) << "Anonymous query through public resolver";
75 if (as
.front() == "127.255.255.255") {
76 LOG(INFO
) << "Excessive Number of Queries";
79 std::cout
<< dom
<< " advice from " << uribl
<< '\n';
81 std::cout
<< " returned: " << aa
<< '\n';
87 void do_addr(DNS::Resolver
& res
, char const* a
)
89 auto const names
= DNS::fcrdns(res
, a
);
90 std::vector
<Domain
> doms
;
91 for (auto const& name
: names
) {
92 doms
.emplace_back(name
);
95 std::cout
<< a
<< " [";
96 std::copy(begin(doms
), end(doms
),
97 std::experimental::make_ostream_joiner(std::cout
, ", "));
101 if (IP4::is_address(a
)) {
102 auto const reversed
{IP4::reverse(a
)};
104 res
.get_strings(DNS::RR_type::PTR
, reversed
+ "in-addr.arpa");
105 for (auto const& ptr
: ptrs
) {
106 std::cout
<< a
<< " has a PTR to " << ptr
<< '\n';
109 if (IP6::is_address(a
)) {
110 auto const reversed
{IP6::reverse(a
)};
112 res
.get_strings(DNS::RR_type::PTR
, reversed
+ "ip6.arpa");
113 for (auto const& ptr
: ptrs
) {
114 std::cout
<< a
<< " has a PTR to " << ptr
<< '\n';
117 std::cout
<< a
<< '\n';
119 if (IP4::is_address(a
)) {
120 check_dnsrbl(res
, a
);
125 get_tlsa_rrs(DNS::Resolver
& res
, Domain
const& domain
, uint16_t port
)
127 auto const tlsa
= fmt::format("_{}._tcp.{}", port
, domain
.ascii());
129 DNS::Query
q(res
, DNS::RR_type::TLSA
, tlsa
);
132 // LOG(INFO) << "TLSA data not found for " << domain << ':' << port;
135 if (q
.bogus_or_indeterminate()) {
136 LOG(WARNING
) << "TLSA data is bogus or indeterminate";
139 auto tlsa_rrs
= q
.get_records();
140 if (!tlsa_rrs
.empty()) {
141 LOG(INFO
) << "### TLSA data found for " << domain
<< ':' << port
<< " ###";
147 void do_domain(DNS::Resolver
& res
, char const* dom_cp
)
149 auto const dom
{Domain
{dom_cp
}};
151 auto cnames
= res
.get_strings(DNS::RR_type::CNAME
, dom
.ascii().c_str());
152 if (!cnames
.empty()) {
153 // RFC 2181 section 10.1. CNAME resource records
154 CHECK_EQ(cnames
.size(), 1);
155 std::cout
<< dom
<< " is an alias for " << cnames
.front() << '\n';
158 auto as
= res
.get_strings(DNS::RR_type::A
, dom
.ascii().c_str());
159 for (auto const& a
: as
) {
160 do_addr(res
, a
.c_str());
163 auto aaaas
= res
.get_strings(DNS::RR_type::AAAA
, dom
.ascii().c_str());
164 for (auto const& aaaa
: aaaas
) {
165 do_addr(res
, aaaa
.c_str());
169 auto tlsa_rrs
{get_tlsa_rrs(res
, dom
, port
)};
170 if (!tlsa_rrs
.empty()) {
171 for (auto const& tlsa_rr
: tlsa_rrs
) {
172 if (std::holds_alternative
<DNS::RR_TLSA
>(tlsa_rr
)) {
173 auto const rp
= std::get
<DNS::RR_TLSA
>(tlsa_rr
);
174 std::cout
<< rp
<< "\n";
177 std::cout
<< "not a RR_TLSA\n";
182 auto q
{DNS::Query
{res
, DNS::RR_type::MX
, dom
.ascii()}};
183 if (!q
.has_record()) {
184 std::cout
<< "no MX records\n";
188 auto reg_dom
{tld_db
.get_registered_domain(dom
.ascii())};
189 if (reg_dom
&& dom
!= reg_dom
) {
190 std::cout
<< "registered domain is " << reg_dom
<< '\n';
193 auto txts
= res
.get_strings(DNS::RR_type::TXT
, dom
.ascii().c_str());
194 for (auto const& txt
: txts
) {
195 std::cout
<< "TXT " << txt
<< '\n';
198 if (q
.has_record()) {
199 check_uribls(res
, dom
.ascii().c_str());
202 if (q
.has_record() && q
.authentic_data()) {
203 std::cout
<< "MX records authentic for domain " << dom
<< '\n';
206 auto mxs
{q
.get_records()};
208 mxs
.erase(std::remove_if(begin(mxs
), end(mxs
),
210 return !std::holds_alternative
<DNS::RR_MX
>(rr
);
215 std::cout
<< "mail for " << dom
<< " is handled by\n";
218 std::sort(begin(mxs
), end(mxs
), [](auto const& a
, auto const& b
) {
219 auto mxa
= std::get
<DNS::RR_MX
>(a
);
220 auto mxb
= std::get
<DNS::RR_MX
>(b
);
221 if (mxa
.preference() == mxb
.preference())
222 return mxa
.exchange() < mxb
.exchange();
223 return mxa
.preference() < mxb
.preference();
226 for (auto const& mx
: mxs
) {
227 if (std::holds_alternative
<DNS::RR_MX
>(mx
)) {
228 auto x
= std::get
<DNS::RR_MX
>(mx
);
229 std::cout
<< std::setfill(' ') << std::setw(3) << x
.preference() << ' '
230 << x
.exchange() << '\n';
235 int main(int argc
, char* argv
[])
237 fs::path config_path
= osutil::get_config_dir();
238 DNS::Resolver
res(config_path
);
240 for (int i
= 1; i
< argc
; ++i
) {
241 auto const arg
= argv
[i
];
242 if (IP::is_address(arg
)) {