2 #include <ail/string.hpp>
5 #include <boost/bind.hpp>
6 #include <boost/foreach.hpp>
12 std::size_t const dns_buffer_size
= 1024;
15 bool dns_request::operator==(dns_request
const & other
) const
17 return transaction_id
== other
.transaction_id
&& name
== other
.name
;
20 dns_client::dns_client(boost::asio::io_service
& io_service
, std::string
const & server
, ushort port
):
21 io_service(io_service
),
26 socket(io_service
, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port
)),
32 void dns_client::lookup(std::string
const & name
, dns_lookup_handler_type lookup_handler
)
34 boost::mutex::scoped_lock
scoped_lock(mutex
);
36 //boost::asio::ip::udp::resolver::query query(server, "dns");
37 boost::asio::ip::udp::resolver::query
query(server
, "53");
40 request
.transaction_id
= current_id
;
42 request
.lookup_handler
= lookup_handler
;
44 pending_requests
.push_back(request
);
47 send_dns_request(request
);
50 resolver
.async_resolve(query
, boost::bind(&dns_client::resolve_event
, this, boost::asio::placeholders::error
, boost::asio::placeholders::iterator
, request
));
57 void dns_client::resolve_event(boost::system::error_code
const & error
, boost::asio::ip::udp::resolver::iterator endpoint_iterator
, dns_request
& request
)
61 boost::mutex::scoped_lock
scoped_lock(mutex
);
63 //std::cout << "Retrieved a DNS endpoint" << std::endl;
65 endpoint
= *endpoint_iterator
;
67 send_dns_request(request
);
70 error_occured(request
, "Unable to resolve DNS server address: " + error
.message());
73 void dns_client::continue_processing(char * receive_buffer
)
75 delete receive_buffer
;
79 void dns_client::receive_event(boost::system::error_code
const & error
, std::size_t bytes_received
, char * receive_buffer
)
81 boost::mutex::scoped_lock
scoped_lock(mutex
);
83 std::string malformed_packet_message
= "DNS server returned a malformed packet (" + number_to_string
<std::size_t>(bytes_received
) + " byte(s))";
87 //std::cout << "Received " << bytes_received << " byte(s)" << std::endl;
89 std::string
packet(receive_buffer
, bytes_received
);
90 bit_reader
reader(packet
);
92 std::size_t word
= 16;
94 ushort transaction_id
;
98 transaction_id
= static_cast<ushort
>(reader
.read(word
));
102 global_error(malformed_packet_message
);
103 continue_processing(receive_buffer
);
107 request_vector::iterator iterator
;
108 if(get_request(transaction_id
, iterator
))
110 dns_lookup_result output
;
111 dns_request
& request
= *iterator
;
112 output
.name
= request
.name
;
116 bool is_response
= reader
.read_bool();
117 ulong opcode
= reader
.read(4);
118 bool authoritative
= reader
.read_bool();
119 bool truncated
= reader
.read_bool();
120 bool recursion_desired
= reader
.read_bool();
121 bool recursion_available
= reader
.read_bool();
123 bool answer_authenticated
= reader
.read_bool();
125 ulong reply_code
= reader
.read(4);
127 ulong questions
= reader
.read(word
);
128 ulong answer_records
= reader
.read(word
);
129 ulong authority_records
= reader
.read(word
);
130 ulong additional_records
= reader
.read(word
);
132 for(ulong i
= 0; i
< questions
; i
++)
133 output
.questions
.push_back(read_question(reader
));
135 for(ulong i
= 0; i
< answer_records
; i
++)
136 output
.answers
.push_back(read_answer(reader
));
138 output
.success
= (answer_records
> 0);
141 BOOST_FOREACH(dns_answer
& answer
, output
.answers
)
145 output
.address
= answer
.address
;
152 error_occured(request
, "DNS reply does not contain any answers");
153 continue_processing(receive_buffer
);
157 for(ulong i
= 0; i
< authority_records
; i
++)
158 output
.authoritative_nameservers
.push_back(read_answer(reader
));
160 for(ulong i
= 0; i
< additional_records
; i
++)
161 output
.additional_records
.push_back(read_answer(reader
));
163 request
.lookup_handler(output
);
167 error_occured(request
, malformed_packet_message
);
171 global_error("Invalid transaction ID returned by DNS server: 0x" + number_to_string
<ushort
>(transaction_id
, std::ios_base::hex
));
174 global_error("Receive error: " + error
.message());
176 continue_processing(receive_buffer
);
179 void dns_client::send_event(boost::system::error_code
const & error
, std::size_t bytes_received
, dns_request
& request
)
181 boost::mutex::scoped_lock
scoped_lock(mutex
);
185 //std::cout << "Send event (" << bytes_received << " bytes), deallocating buffer" << std::endl;
188 error_occured(request
, "Unable to send data to DNS server");
190 delete request
.buffer
;
193 void dns_client::receive_data()
195 char * receive_buffer
= new char[dns_buffer_size
];
196 socket
.async_receive_from(boost::asio::buffer(receive_buffer
, dns_buffer_size
), endpoint
, boost::bind(&dns_client::receive_event
, this, boost::asio::placeholders::error
, boost::asio::placeholders::bytes_transferred
, receive_buffer
));
200 void dns_client::send_dns_request(dns_request
& request
)
202 string_vector tokens
= ail::tokenise(request
.name
, ".");
205 big_endian_string(request
.transaction_id
, 2) +
206 std::string("\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00", 10);
208 BOOST_FOREACH(std::string
const & current_token
, tokens
)
209 packet
+= big_endian_string(static_cast<ulong
>(current_token
.size()), 1) + current_token
;
211 packet
+= std::string("\x00\x00\x01\x00\x01", 5);
213 std::size_t packet_size
= packet
.size();
214 request
.buffer
= new char[packet_size
];
215 std::memcpy(request
.buffer
, packet
.c_str(), packet_size
);
217 socket
.async_send_to(boost::asio::buffer(request
.buffer
, packet_size
), endpoint
, boost::bind(&dns_client::send_event
, this, boost::asio::placeholders::error
, boost::asio::placeholders::bytes_transferred
, request
));
221 void dns_client::global_error(std::string
const & message
)
223 BOOST_FOREACH(dns_request
& request
, pending_requests
)
225 dns_lookup_result result
;
226 result
.success
= false;
227 result
.error_message
= message
;
228 request
.lookup_handler(result
);
230 pending_requests
.clear();
233 void dns_client::error_occured(dns_request
& request
, std::string
const & message
)
235 dns_lookup_result result
;
236 result
.success
= false;
237 result
.name
= request
.name
;
238 result
.error_message
= message
;
239 request
.lookup_handler(result
);
240 erase_request(request
);
243 void dns_client::erase_request(dns_request
& request
)
245 for(request_vector::iterator i
= pending_requests
.begin(), end
= pending_requests
.end(); i
!= end
; i
++)
249 pending_requests
.erase(i
);
255 bool dns_client::get_request(ushort transaction_id
, request_vector::iterator
& output
)
257 for(request_vector::iterator i
= pending_requests
.begin(), end
= pending_requests
.end(); i
!= end
; i
++)
259 if(i
->transaction_id
== transaction_id
)
268 dns_question
dns_client::read_question(bit_reader
& reader
)
271 output
.name
= read_name(reader
);
272 output
.type
= reader
.read_bytes(2);
273 output
.dns_class
= reader
.read_bytes(2);
274 //std::cout << "Question: " << output.name << std::endl;
278 dns_answer
dns_client::read_answer(bit_reader
& reader
)
281 output
.name
= read_name(reader
);
282 output
.type
= reader
.read_bytes(2);
283 output
.dns_class
= reader
.read_bytes(2);
284 output
.time_to_live
= reader
.read_bytes(4);
285 output
.is_unknown
= false;
287 ulong data_length
= reader
.read_bytes(2);
294 ulong numeric_ip
= reader
.read_bytes(4);
295 output
.address
= convert_ipv4(numeric_ip
);
302 output
.address
= convert_ipv6(reader
.string(16));
305 //NS, nameserver, name
308 //CNAME, canonical name, name
310 output
.address
= read_name(reader
);
315 output
.is_unknown
= true;
316 output
.other_data
= reader
.string(data_length
);
323 std::string
dns_client::read_name(bit_reader
& reader
)
327 bool fix_offset
= false;
328 std::size_t final_offset
;
330 bool is_first
= true;
333 ulong length
= reader
.read_bytes(1);
338 ulong subtrahend
= 0xc000;
339 ulong new_offset
= ((length
<< bits_per_byte
) | reader
.read_bytes(1)) - subtrahend
;
343 final_offset
= reader
.get_offset();
345 reader
.set_offset(bits_per_byte
* new_offset
);
352 address
+= reader
.string(length
);
356 reader
.set_offset(final_offset
);
358 //std::cout << "Read name: " << address << std::endl;