Tamer
C++ language extensions for event-driven programming
Loading...
Searching...
No Matches
dns.hh
1#ifndef TAMER_DNS_HH
2#define TAMER_DNS_HH 1
3#include <tamer/tamer.hh>
4#include <tamer/fd.hh>
5#include <tamer/ref.hh>
6#include <arpa/inet.h>
7#include <map>
8#include <list>
9#include <set>
10#include <sstream>
11#include <cstring>
12#include <cstdio>
13#include <cstdlib>
14#include <climits>
15
16
17#define DNS_REPARSE_TIME 60
18
19#define DNS_OPTION_SEARCH 1
20#define DNS_OPTION_NAMESERVERS 2
21#define DNS_OPTION_MISC 4
22#define DNS_OPTIONS_ALL 7
23
24/* no error */
25#define DNS_ERR_NONE 0
26/* name server was unable to interpret the query */
27#define DNS_ERR_FORMAT 1
28/* name server was unable to process this query due to a problem with the name server */
29#define DNS_ERR_SERVERFAILED 2
30/* domain name does not exist */
31#define DNS_ERR_NOTEXIST 3
32/* name server does not support the requested kind of query */
33#define DNS_ERR_NOTIMPL 4
34/* name server refuses to perform the specified operation for policy reasons */
35#define DNS_ERR_REFUSED 5
36/* an unknown error occurred */
37#define DNS_ERR_UNKNOWN 16
38/* reply was truncated */
39#define DNS_ERR_TRUNCATED 17
40
41#define CLASS_INET 1
42#define TYPE_A 1
43#define TYPE_PTR 12
44
45namespace tamer {
46namespace dns {
47
48class packet_imp;
49struct reply_imp;
50struct search_list_imp;
51class request_imp;
52class nameserver_imp;
53
54typedef ref_ptr<packet_imp> packet;
55typedef ref_ptr<reply_imp> reply;
56typedef ref_ptr<search_list_imp> search_list;
57typedef ref_ptr<request_imp> request;
58typedef ref_ptr<nameserver_imp> nameserver;
59
60}
61
62void gethostbyname(std::string name, bool search, event<dns::reply> result);
63void gethostbyaddr(struct in_addr *in, event<dns::reply> result);
64
65namespace dns {
66
67packet make_packet(size_t size);
68packet make_packet(uint8_t * buf, size_t size);
69reply make_reply(packet p);
70search_list make_search_list(int ndots);
71request make_request_a(std::string name, bool search = false, search_list s = search_list());
72request make_request_ptr(struct in_addr *in);
73nameserver make_nameserver(uint32_t addr, int port = 53);
74
75class packet_imp : public enable_ref_ptr_with_full_release<packet_imp> {
76public:
77 struct _strlen_t { int len; _strlen_t(int l) : len(l) {}};
78
79private:
80 typedef void (packet_imp::*unspecified_bool_type)() const;
81 void unspecified_method() const {}
82
83 off_t _off;
84 ssize_t _fill;
85 ssize_t _max;
86 uint8_t * _buf;
87 _strlen_t _strlen;
88
89 void expand() { if (_off > _fill) _fill = _off; }
90
91public:
92 packet_imp(size_t size);
93 packet_imp(uint8_t * buf, size_t size);
94 void full_release();
95
96 operator unspecified_bool_type() const;
97
98 static _strlen_t set_strlen(int len);
99 packet_imp &operator>>(_strlen_t _strlen);
100 packet_imp &operator<<(_strlen_t _strlen);
101
102 void reset();
103 ssize_t size() const;
104 off_t offset() const;
105 packet_imp &operator+=(unsigned int p);
106
107 const uint8_t * getbuf() const;
108
109 packet_imp &operator>>(uint8_t &val);
110 packet_imp &operator>>(uint16_t &val);
111 packet_imp &operator>>(uint32_t &val);
112 packet_imp &operator>>(struct in_addr &val);
113 packet_imp &operator>>(std::string &val);
114
115 packet_imp &operator<<(uint8_t val);
116 packet_imp &operator<<(uint16_t val);
117 packet_imp &operator<<(uint32_t val);
118 packet_imp &operator<<(std::string val);
119};
120
121inline packet make_packet(size_t size) {
122 return packet(new packet_imp(size));
123}
124
125inline packet make_packet(uint8_t * buf, size_t size) {
126 return packet(new packet_imp(buf, size));
127}
128
129inline packet_imp::packet_imp(size_t size)
130 : _off(0), _fill(0), _max(size), _buf(new uint8_t[size]), _strlen(_strlen_t(-1)) {
131 memset(_buf, 0, size);
132}
133
134inline packet_imp::packet_imp(uint8_t * buf, size_t size)
135 : _off(0), _fill(size), _max(size), _buf(new uint8_t[size]), _strlen(_strlen_t(-1)) {
136 memcpy(_buf, buf, size);
137}
138
139inline packet_imp::operator unspecified_bool_type() const {
140 return (_off > _max || _fill > _max) ? 0 : &packet_imp::unspecified_method;
141}
142
143inline void packet_imp::full_release() {
144 delete [] _buf;
145}
146
147inline packet_imp::_strlen_t packet_imp::set_strlen(int len) {
148 return _strlen_t(len);
149}
150
151inline packet_imp &packet_imp::operator>>(_strlen_t s) {
152 _strlen = s;
153 return *this;
154}
155
156inline packet_imp &packet_imp::operator<<(_strlen_t s) {
157 _strlen = s;
158 return *this;
159}
160inline void packet_imp::reset() {
161 _off = 0;
162}
163
164inline ssize_t packet_imp::size() const {
165 return _fill;
166}
167
168inline off_t packet_imp::offset() const {
169 return _off;
170}
171
172inline packet_imp &packet_imp::operator+=(unsigned int p) {
173 _off += p;
174 expand();
175 return *this;
176}
177
178inline const uint8_t * packet_imp::getbuf() const {
179 return _buf;
180}
181
182inline packet_imp &packet_imp::operator>>(uint8_t &val) {
183 val = _buf[_off];
184 _off += sizeof(uint8_t);
185 return *this;
186}
187
188inline packet_imp &packet_imp::operator>>(uint16_t &val) {
189 val = htons(*(uint16_t *)&_buf[_off]);
190 _off += sizeof(uint16_t);
191 return *this;
192}
193
194inline packet_imp &packet_imp::operator>>(uint32_t &val) {
195 val = htonl(*(uint32_t *)&_buf[_off]);
196 _off += sizeof(uint32_t);
197 return *this;
198}
199
200inline packet_imp &packet_imp::operator>>(struct in_addr &val) {
201 val.s_addr = *(uint32_t *)&_buf[_off];
202 _off += sizeof(uint32_t);
203 return *this;
204}
205
206inline packet_imp &packet_imp::operator>>(std::string &val) {
207 if (_strlen.len < 0) {
208 val = std::string((char *)&_buf[_off]);
209 _off += val.length() + 1;// for \0 byte
210 } else {
211 val = std::string((char *)&_buf[_off], _strlen.len);
212 _off += _strlen.len;
213 _strlen.len = -1;
214 }
215 return *this;
216}
217
218inline packet_imp &packet_imp::operator<<(uint8_t val) {
219 _buf[_off] = val;
220 _off += sizeof(uint8_t);
221 expand();
222 assert(*this);
223 return *this;
224}
225
226inline packet_imp &packet_imp::operator<<(uint16_t val) {
227 *(uint16_t *)&_buf[_off] = htons(val);
228 _off += sizeof(uint16_t);
229 expand();
230 assert(*this);
231 return *this;
232}
233
234inline packet_imp &packet_imp::operator<<(uint32_t val) {
235 *(uint32_t *)&_buf[_off] = htonl(val);
236 _off += sizeof(uint32_t);
237 expand();
238 assert(*this);
239 return *this;
240}
241
242inline packet_imp &packet_imp::operator<<(std::string val) {
243 if (_strlen.len < 0) {
244 strcpy((char *)&_buf[_off], val.c_str());
245 _off += val.length();
246 } else {
247 memcpy(&_buf[_off], val.c_str(), _strlen.len);
248 _off += _strlen.len;
249 _strlen.len = -1;
250 }
251 expand();
252 assert(*this);
253 return *this;
254}
255
256struct reply_imp : public enable_ref_ptr {
257private:
258 typedef void (reply_imp::*unspecified_bool_type)() const;
259 void unspecified_method() const {};
260
261public:
262 int err;
263 uint16_t trans_id;
264 uint32_t ttl;
265 std::vector<uint32_t> addrs;
266 std::string name;
267
268 reply_imp(packet p);
269 operator unspecified_bool_type() const;
270
271private:
272 static int skip_name(ref_ptr<packet_imp> &p);
273};
274
275inline reply make_reply(packet p) {
276 return reply(new reply_imp(p));
277}
278
279inline reply_imp::operator unspecified_bool_type() const {
280 return (err) ? 0 : &reply_imp::unspecified_method;
281}
282
283inline int reply_imp::skip_name(ref_ptr<packet_imp> &p) {
284 uint8_t len;
285
286 while(*p) {
287 *p >> len;
288 if (!len) break; // done
289 if (len & 0xC0){ *p += 1; break; } // pointer
290 if (len > 63) return -1; // label too long
291 *p += len;
292 }
293
294 return *p ? 0 : -1; // read past the buffer?
295}
296
297struct search_list_imp : public enable_ref_ptr {
298 int ndots;
299 std::list<std::string> domains;
300 search_list_imp(int n) : ndots(n) {}
301};
302
303inline search_list make_search_list(int ndots) {
304 return search_list(new search_list_imp(ndots));
305}
306
307class request_imp : public enable_ref_ptr {
308 typedef void (request_imp::*unspecified_bool_type)() const;
309 void unspecified_method() const {}
310
311protected:
312 uint16_t _type;
313
314 int _err;
315 int _tx_count;
316 bool _sent_raw;
317
318 uint16_t _trans_id;
319 std::string _curr_name;
320
321public:
322 request_imp(uint16_t type);
323 virtual ~request_imp() {};
324 operator unspecified_bool_type() const;
325 int error() const;
326 int tx_count() const;
327 uint16_t trans_id() const;
328
329 virtual bool hasnext() const = 0;
330 virtual void next(uint16_t trans_id) = 0;
331 void reissue(uint16_t trans_id);
332
333 int getpacket(packet &p, bool tcp = false);
334};
335
336inline request_imp::request_imp(uint16_t type)
337 : _type(type), _err(-1), _tx_count(0), _sent_raw(0), _trans_id(0xFFFF) {
338}
339
340inline request_imp::operator unspecified_bool_type() const {
341 return (_err) ? 0 : &request_imp::unspecified_method;
342}
343
344inline int request_imp::error() const {
345 return _err;
346}
347
348inline int request_imp::tx_count() const {
349 return _tx_count;
350}
351
352inline uint16_t request_imp::trans_id() const {
353 return _trans_id;
354}
355
356inline void request_imp::reissue(uint16_t trans_id) {
357 _trans_id = trans_id;
358 _tx_count++;
359}
360
361class request_a : public request_imp {
362 int _search;
363 std::string _name;
364
365 int _ndots;
366 search_list _s;
367 std::list<std::string>::const_iterator _doms_it;
368
369 static bool check_name(std::string name);
370
371public:
372 request_a(std::string name, bool search = false, search_list s = search_list());
373 ~request_a() {}
374 bool hasnext() const;
375 void next(uint16_t trans_id);
376};
377
378inline request make_request_a(std::string name, bool search, search_list s) {
379 return request(new request_a(name, search, s));
380}
381
382inline request_a::request_a(std::string name, bool search, search_list s)
383 : request_imp(TYPE_A), _search(search), _name(name), _ndots(0), _s(s) {
384
385 if ((_err = check_name(name) ? 0 : -1))
386 return;
387
388 if (search) {
389 _doms_it = _s->domains.begin();
390 for (int i = name.find('.', 0); i >= 0; i = name.find('.', i + 1))
391 _ndots++;
392 }
393}
394
395inline bool request_a::hasnext() const {
396 return (!_sent_raw || (_search && _doms_it != _s->domains.end())) ? 1 : 0;
397}
398
399inline bool request_a::check_name(std::string name) {
400 size_t i = 0;
401 if (name.size() > 255)
402 return false;
403 for (size_t p = name.find('.'); p != std::string::npos; i = p + 1, p = name.find('.', i))
404 if (p - i > 63)
405 return false;
406 if (name.size() - i > 63)
407 return false;
408 return true;
409}
410
411class request_ptr : public request_imp {
412public:
413 request_ptr(struct in_addr * addr);
414 ~request_ptr() {}
415 bool hasnext() const;
416 void next(uint16_t trans_id);
417};
418
419inline request make_request_ptr(struct in_addr *in) {
420 return request(new request_ptr(in));
421}
422
423inline request_ptr::request_ptr(struct in_addr * addr) : request_imp(TYPE_PTR) {
424 std::ostringstream s;
425 uint32_t a;
426
427 _err = 0;
428
429 a = ntohl(addr->s_addr);
430 s << (int)((a )&0xff) << "." <<
431 (int)((a>>8 )&0xff) << "." <<
432 (int)((a>>16)&0xff) << "." <<
433 (int)((a>>24)&0xff) << ".in-addr.arpa";
434 _curr_name = s.str();
435}
436
437inline bool request_ptr::hasnext() const {
438 return !_sent_raw;
439}
440
441class nameserver_imp
442 : public enable_ref_ptr_with_full_release<nameserver_imp> {
443public:
444 int timeouts;
445 std::list<reply> received;
446 event<int> ready;
447
448private:
449 typedef void (nameserver_imp::*unspecified_bool_type)() const;
450 void unspecified_method() const {}
451
452 uint32_t _addr;
453 int _port;
454
455 std::list<packet> _tcp_outgoing;
456 int _tcp_outbound;
457
458 tamer::fd _udp;
459 tamer::fd _tcp;
460
461public:
462 nameserver_imp(uint32_t addr, int port);
463
464 operator unspecified_bool_type() const;
465 bool operator< (const nameserver_imp &n2) const;
466
467 void full_release() {
468 if (ready) ready.trigger(-1);
469 if (_udp) _udp.close();
470 if (_tcp) _tcp.close();
471 }
472
473 void print() {
474 struct in_addr ina;
475 ina.s_addr = _addr;
476 printf("ns: %s\n", inet_ntoa(ina));
477 }
478
479 void init(event<int> e);
480 void init_tcp(event<int> e, timeval timeout);
481 void query(packet p);
482 void query_tcp(packet p, timeval timeout);
483
484private:
485 class closure__init__Qi_;
486 void init(closure__init__Qi_ &);
487
488 class closure__init_tcp__Qi_7timeval;
489 void init_tcp(closure__init_tcp__Qi_7timeval &);
490
491 class closure__query__6packet;
492 void query(closure__query__6packet&);
493
494 class closure__query_tcp__6packet7timeval;
495 void query_tcp(closure__query_tcp__6packet7timeval&);
496};
497
498class nameserver_comp {
499public:
500 bool operator() (const nameserver &n1, const nameserver &n2) const {
501 return *n1 < *n2;
502 }
503};
504
505typedef std::set<nameserver, nameserver_comp> nameservers;
506
507inline nameserver make_nameserver(uint32_t addr, int port) {
508 return nameserver(new nameserver_imp(addr, port));
509}
510
511inline nameserver_imp::nameserver_imp(uint32_t addr, int port)
512 : timeouts(0), _addr(addr), _port(port), _tcp_outbound(0) {
513}
514
515inline nameserver_imp::operator unspecified_bool_type() const {
516 return (!_udp) ? 0 : &nameserver_imp::unspecified_method;
517}
518
519inline bool nameserver_imp::operator< (const nameserver_imp &n) const {
520 return _addr < n._addr || (_addr == n._addr && _port < n._port);
521}
522
524
525struct query {
526 request q;
527 event<reply> p;
528 query() : q(), p() {}
529 query(request q, event<reply> p) : q(q), p(p) {}
530 operator uint16_t() { return q->trans_id(); }
531};
532
533class resolver : public enable_ref_ptr_with_full_release<resolver> {
534 typedef void (resolver::*unspecified_bool_type)() const;
535 void unspecified_method() const {}
536
537 std::string _rcname;
538 int _flags;
539
540 timeval _timeout;
541 int _ndots;
542 int _max_retransmits;
543 int _max_timeouts;
544 int _max_reqs_inflight;
545 search_list _search_list;
546
547 int _err;
548 int _reqs_inflight;
549 struct stat _fst;
550
551 std::map<uint16_t, query> _requests;
552
553 nameservers _nameservers;
554 nameservers _failed;
555 nameservers::iterator _nsindex;
556 event<> _init;
557 bool _is_init;
558
559 event<> _reparse;
560
561 uint16_t get_trans_id();
562
563 void resolve(request q, event<reply> e);
564
565 void add_nameservers(nameservers n, event<>);
566 void handle_nameserver(nameserver n);
567 void failed_nameserver(nameserver n);
568 nameserver next_nameserver();
569
570 void parse_loop();
571 void parse();
572
573 void set_default(event<> e);
574 void set_default_options();
575 void set_option(const char * option);
576 void set_from_hostname();
577 void add_domain(const char * name);
578
579 static int strtoint(const char * val, int min, int max);
580 static char * next_line(char *buf);
581
582 class closure__ready__Q_;
583 void ready(closure__ready__Q_&);
584
585 class closure__parse_loop;
586 void parse_loop(closure__parse_loop&);
587
588 class closure__parse;
589 void parse(closure__parse&);
590
591 class closure__resolve__7requestQ5reply_;
592 void resolve(closure__resolve__7requestQ5reply_&);
593
594 class closure__add_nameservers__11nameserversQ_;
595 void add_nameservers(closure__add_nameservers__11nameserversQ_&);
596
597 class closure__failed_nameserver__10nameserver;
598 void failed_nameserver(closure__failed_nameserver__10nameserver&);
599
600 class closure__handle_nameserver__10nameserver;
601 void handle_nameserver(closure__handle_nameserver__10nameserver&);
602
603#if defined(HOST_NAME_MAX)
604 enum { host_name_max = HOST_NAME_MAX };
605#elif defined(_POSIX_HOST_NAME_MAX)
606 enum { host_name_max = _POSIX_HOST_NAME_MAX };
607#else
608 enum { host_name_max = 255 };
609#endif
610
611 public:
612 resolver(int flags, std::string rc = "/etc/resolv.conf");
613
614 operator unspecified_bool_type() const;
615 int error() const;
616
617 void ready(event<> e);
618 void resolve_a(std::string name, bool search, event<reply> e);
619 void resolve_ptr(struct in_addr *in, event<reply> e);
620
621 void full_release();
622};
623
624inline resolver::resolver(int flags, std::string rc)
625 : _rcname(rc), _flags(flags), _err(0), _reqs_inflight(0),
626 _fst(), _nsindex(_nameservers.begin()), _is_init(false) {
627 struct timeval tv;
628 set_default_options();
629 gettimeofday(&tv, NULL);
630 srand(tv.tv_usec);
631 parse_loop();
632}
633
634inline resolver::operator unspecified_bool_type() const {
635 return (_err) ? 0 : &resolver::unspecified_method;
636}
637
638inline int resolver::error() const {
639 return _err;
640}
641
642inline void resolver::resolve_a(std::string name, bool search, event<reply> e) {
643 request q;
644
645 q = make_request_a(name, search, _search_list);
646 if (!*q)
647 e.trigger(reply());
648 else
649 resolve(q, e);
650}
651
652inline void resolver::resolve_ptr(struct in_addr *in, event<reply> e) {
653 request q;
654
655 q = make_request_ptr(in);
656 resolve(q, e);
657}
658
659inline void resolver::full_release() {
660 _nameservers.clear();
661 _failed.clear();
662 for (std::map<uint16_t, query >::iterator i = _requests.begin();
663 i != _requests.end(); i++)
664 i->second.p.trigger(reply());
665 _requests.clear();
666}
667
668inline nameserver resolver::next_nameserver() {
669 nameserver n;
670 assert(_nameservers.size());
671 if (_nsindex == _nameservers.end())
672 _nsindex = _nameservers.begin();
673 n = *_nsindex;
674 _nsindex++;
675 return n;
676}
677
678//TODO use preprocessor constants
679inline void resolver::set_default_options() {
680 _ndots = 1;
681 _timeout.tv_sec = 5;
682 _timeout.tv_usec = 0;
683 _max_retransmits = 1;
684 _max_timeouts = 3;
685 _max_reqs_inflight = 64;
686}
687
688inline void resolver::set_from_hostname() {
689 char hostname[host_name_max + 1];
690 char *domainname;
691
692 _search_list = make_search_list(_ndots);
693 if (gethostname(hostname, sizeof(hostname))) return;
694 domainname = strchr(hostname, '.');
695 if (!domainname) return;
696 add_domain(domainname);
697}
698
699inline void resolver::add_domain(const char * name) {
700 assert(_search_list);
701 _search_list->domains.push_back(name);
702}
703
704inline int resolver::strtoint(const char * val, int min, int max) {
705 char *end;
706 int r = strtol(val, &end, 10);
707
708 if (*end)
709 return -1;
710 else if (r < min)
711 return min;
712 else if (r > max)
713 return max;
714 else
715 return r;
716}
717
718inline char* resolver::next_line(char * buf) {
719 char *r;
720 return (r = strchr(buf, '\n')) ? (*r = 0) + r + 1 : 0;
721}
722
723}}
724#endif /* TAMER_DNS_HH */
A future occurrence.
Definition event.hh:116
Event-based file descriptor wrapper class.
Namespace containing public Tamer classes and functions for the Tamer core.
Definition adapter.hh:17
The main Tamer header file.