Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include <boost/bind/bind.hpp>
6 : #include <bind/bind_util.h>
7 : #include <base/address_util.h>
8 : #include <bind/bind_resolver.h>
9 :
10 : using namespace boost::placeholders;
11 :
12 : BindResolver *BindResolver::resolver_;
13 :
14 16 : void BindResolver::Init(boost::asio::io_context &io,
15 : const std::vector<DnsServer> &dns_servers,
16 : uint16_t client_port, Callback cb, uint8_t dscp) {
17 16 : assert(resolver_ == NULL);
18 16 : resolver_ = new BindResolver(io, dns_servers, client_port, cb, dscp);
19 16 : }
20 :
21 16 : void BindResolver::Shutdown() {
22 16 : if (resolver_) {
23 16 : delete resolver_;
24 16 : resolver_ = NULL;
25 : }
26 16 : }
27 :
28 16 : BindResolver::BindResolver(boost::asio::io_context &io,
29 : const std::vector<DnsServer> &dns_servers,
30 : uint16_t client_port, Callback cb,
31 16 : uint8_t dscp)
32 16 : : pkt_buf_(NULL), cb_(cb), sock_(io), dscp_value_(dscp) {
33 :
34 16 : boost::system::error_code ec;
35 16 : uint8_t size = (dns_servers.size() > max_dns_servers) ?
36 16 : dns_servers.size() : max_dns_servers;
37 16 : dns_ep_.resize(size);
38 32 : for (unsigned int i = 0; i < dns_servers.size(); ++i) {
39 : boost::asio::ip::address dns_address(
40 16 : AddressFromString(dns_servers[i].ip_, &ec));
41 : boost::asio::ip::udp::endpoint *ep =
42 16 : new boost::asio::ip::udp::endpoint(dns_address, dns_servers[i].port_);
43 16 : assert (ec.value() == 0);
44 16 : dns_ep_[i] = ep;
45 : }
46 :
47 : boost::asio::ip::udp::endpoint local_ep(boost::asio::ip::address::
48 32 : from_string("0.0.0.0", ec),
49 16 : client_port);
50 16 : sock_.open(boost::asio::ip::udp::v4(), ec);
51 16 : assert(ec.value() == 0);
52 16 : sock_.bind(local_ep, ec);
53 16 : if (ec.value() != 0) {
54 15 : local_ep.port(0);
55 15 : sock_.bind(local_ep, ec);
56 15 : assert(ec.value() == 0);
57 : }
58 16 : if (dscp_value_) {
59 0 : SetDscpSocketOption();
60 : }
61 16 : AsyncRead();
62 16 : }
63 :
64 0 : void BindResolver::SetDscpSocketOption() {
65 : /* The dscp_value_ field is expected to have DSCP value between 0 and 63 ie
66 : * in the lower order 6 bits of a byte. However, setsockopt expects DSCP
67 : * value in upper 6 bits of a byte. Hence left shift the value by 2 digits
68 : * before passing it to setsockopt */
69 0 : uint8_t value = dscp_value_ << 2;
70 0 : int retval = setsockopt(sock_.native_handle(), IPPROTO_IP, IP_TOS,
71 : reinterpret_cast<const char *>(&value), sizeof(value));
72 0 : if (retval < 0) {
73 0 : DNS_BIND_TRACE(DnsBindError, "Setting DSCP bits on socket failed for "
74 : << dscp_value_ << " with errno " << strerror(errno));
75 : }
76 0 : }
77 :
78 0 : void BindResolver::SetDscpValue(uint8_t val) {
79 0 : dscp_value_ = val;
80 0 : SetDscpSocketOption();
81 0 : }
82 :
83 0 : uint8_t BindResolver::GetDscpValue() {
84 0 : uint8_t dscp = 0;
85 0 : unsigned int optlen = sizeof(dscp);
86 0 : int retval = getsockopt(sock_.native_handle(), IPPROTO_IP, IP_TOS,
87 : reinterpret_cast<char *>(&dscp),
88 : reinterpret_cast<socklen_t *>(&optlen));
89 0 : if (retval < 0) {
90 0 : DNS_BIND_TRACE(DnsBindError, "Getting DSCP bits on socket failed "
91 : "with errno " << strerror(errno));
92 : }
93 0 : return dscp;
94 : }
95 :
96 32 : BindResolver::~BindResolver() {
97 16 : boost::system::error_code ec;
98 16 : sock_.cancel(ec);
99 16 : sock_.close(ec);
100 48 : for (unsigned int i = 0; i < dns_ep_.size(); ++i) {
101 32 : delete dns_ep_[i];
102 32 : dns_ep_[i] = NULL;
103 : }
104 16 : resolver_ = NULL;
105 16 : if (pkt_buf_) delete [] pkt_buf_;
106 32 : }
107 :
108 0 : void BindResolver::SetupResolver(const DnsServer &server, uint8_t idx) {
109 0 : if (idx >= max_dns_servers) {
110 0 : DNS_BIND_TRACE(DnsBindError, "BindResolver doesnt support more than " <<
111 : max_dns_servers << " servers; ignoring request for " <<
112 : idx);
113 0 : return;
114 : }
115 :
116 0 : if (idx < dns_ep_.size() && dns_ep_[idx]) {
117 0 : delete dns_ep_[idx];
118 0 : dns_ep_[idx] = NULL;
119 : }
120 :
121 0 : boost::system::error_code ec;
122 : boost::asio::ip::udp::endpoint *ep = new boost::asio::ip::udp::endpoint(
123 0 : AddressFromString(server.ip_, &ec), server.port_);
124 0 : assert (ec.value() == 0);
125 0 : dns_ep_[idx] = ep;
126 : }
127 :
128 0 : bool BindResolver::DnsSend(uint8_t *pkt, unsigned int dns_srv_index,
129 : std::size_t len) {
130 0 : if (dns_srv_index < dns_ep_.size() && dns_ep_[dns_srv_index] && len > 0) {
131 0 : sock_.async_send_to(
132 0 : boost::asio::buffer(pkt, len), *dns_ep_[dns_srv_index],
133 0 : boost::bind(&BindResolver::DnsSendHandler, this,
134 : boost::asio::placeholders::error,
135 : boost::asio::placeholders::bytes_transferred, pkt));
136 0 : return true;
137 : } else {
138 0 : DNS_BIND_TRACE(DnsBindError, "Invalid server index: " << dns_srv_index
139 : << ";");
140 0 : delete [] pkt;
141 0 : return false;
142 : }
143 : }
144 :
145 0 : bool BindResolver::DnsSend(uint8_t *pkt, boost::asio::ip::udp::endpoint ep,
146 : std::size_t len) {
147 0 : if (len > 0) {
148 0 : sock_.async_send_to(
149 0 : boost::asio::buffer(pkt, len),ep,
150 0 : boost::bind(&BindResolver::DnsSendHandler, this,
151 : boost::asio::placeholders::error,
152 : boost::asio::placeholders::bytes_transferred, pkt));
153 0 : return true;
154 : } else {
155 0 : DNS_BIND_TRACE(DnsBindError, "Invalid length of packet: " << len
156 : << ";");
157 0 : delete [] pkt;
158 0 : return false;
159 : }
160 : }
161 :
162 0 : void BindResolver::DnsSendHandler(const boost::system::error_code &error,
163 : std::size_t length, uint8_t *pkt) {
164 0 : if (error)
165 0 : DNS_BIND_TRACE(DnsBindError, "Error sending packet to DNS server : " <<
166 : boost::system::system_error(error).what() << ";");
167 0 : delete [] pkt;
168 0 : }
169 :
170 16 : void BindResolver::AsyncRead() {
171 16 : pkt_buf_ = new uint8_t[max_pkt_size];
172 16 : sock_.async_receive(boost::asio::buffer(pkt_buf_, max_pkt_size),
173 16 : boost::bind(&BindResolver::DnsRcvHandler, this,
174 : boost::asio::placeholders::error,
175 : boost::asio::placeholders::bytes_transferred));
176 16 : }
177 :
178 1 : void BindResolver::DnsRcvHandler(const boost::system::error_code &error,
179 : std::size_t length) {
180 1 : bool del = false;
181 1 : if (!error) {
182 0 : if (cb_)
183 0 : cb_(pkt_buf_, length);
184 : else
185 0 : del = true;
186 : } else {
187 1 : DNS_BIND_TRACE(DnsBindError, "Error receiving DNS response : " <<
188 : boost::system::system_error(error).what() << ";");
189 1 : if (error.value() == boost::asio::error::operation_aborted) {
190 1 : return;
191 : }
192 0 : del = true;
193 : }
194 0 : if (del) delete [] pkt_buf_;
195 0 : pkt_buf_ = NULL;
196 0 : AsyncRead();
197 : }
|