-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathresolver.cpp
105 lines (87 loc) · 2.89 KB
/
resolver.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <fstream>
#include <sstream>
#include <iterator>
#include <iomanip>
#include <stdexcept>
#include <boost/asio/ip/udp.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/format.hpp>
#include "resolver.hpp"
#include "dns.hpp"
#include "network_stream.hpp"
namespace dns {
void resolver::add_nameserver(const std::string & nameserver)
{
nameservers_.push_back(nameserver);
}
void resolver::set_nameserver(const std::string & nameserver)
{
nameservers_.clear();
nameservers_.push_back(nameserver);
}
void resolver::set_nameservers(const std::vector<std::string> & nameservers)
{
nameservers_.assign(nameservers.begin(), nameservers.end());
}
void get_nameservers(std::vector<std::string> & nameservers)
{
std::ifstream fdns("/etc/resolv.conf", std::ifstream::in);
std::string line;
while (getline(fdns, line)) {
boost::trim(line);
if ('#' == line[0])
continue;
std::vector<std::string> tokens;
boost::split(tokens, line, boost::algorithm::is_any_of(" \t"), boost::algorithm::token_compress_on);
if (tokens.size() != 2)
continue;
if (tokens.front() != "nameserver")
continue;
nameservers.push_back(tokens.back());
}
}
hostent resolver::gethostbyname(const std::string & hostname) const
{
using boost::asio::ip::udp;
if (nameservers_.empty()) {
get_nameservers(nameservers_);
if (nameservers_.empty())
throw std::runtime_error("No one nameserver");
}
dns::impl::packet_t packet = dns::impl::make_query_packet(hostname);
network::serializer serializer;
serializer << packet;
boost::asio::io_service io_service;
udp::socket udp_sock(io_service);
udp_sock.open(udp::v4());
udp::endpoint destination(
boost::asio::ip::address::from_string(nameservers_.front()), 53);
udp_sock.send_to(boost::asio::buffer(serializer.buffer()), destination);
std::vector<uint8_t> input(0xffff);
dns::impl::packet_t input_packet;
boost::system::error_code error;
size_t len = udp_sock.receive_from(boost::asio::buffer(input), destination, 0, error);
if (error)
throw std::runtime_error(str(boost::format("%1%") % error));
if (!len)
throw std::runtime_error("No input");
network::deserializer deserializer(input);
deserializer >> input_packet;
hostent rv;
rv.name = input_packet.query.name;
for (auto & ans : input_packet.answers) {
switch (ans.type) {
case impl::resource_record_t::T_CNAME:
rv.aliases.push_back(boost::get<std::string>(ans.rdata));
break;
case impl::resource_record_t::T_A:
rv.addresses.push_back(boost::get< std::vector<uint8_t> >(ans.rdata));
break;
default:
std::cerr << "Unknown type of answer: " << ans.type << std::endl;
}
}
return rv;
}
}