aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon/llares.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/llcommon/llares.cpp776
1 files changed, 776 insertions, 0 deletions
diff --git a/linden/indra/llcommon/llares.cpp b/linden/indra/llcommon/llares.cpp
new file mode 100644
index 0000000..3118830
--- /dev/null
+++ b/linden/indra/llcommon/llares.cpp
@@ -0,0 +1,776 @@
1/**
2 * @file llares.cpp
3 * @author Bryan O'Sullivan
4 * @date 2007-08-15
5 * @brief Wrapper for asynchronous DNS lookups.
6 *
7 * $LicenseInfo:firstyear=2007&license=viewergpl$
8 *
9 * Copyright (c) 2007, Linden Research, Inc.
10 *
11 * Second Life Viewer Source Code
12 * The source code in this file ("Source Code") is provided by Linden Lab
13 * to you under the terms of the GNU General Public License, version 2.0
14 * ("GPL"), unless you have obtained a separate licensing agreement
15 * ("Other License"), formally executed by you and Linden Lab. Terms of
16 * the GPL can be found in doc/GPL-license.txt in this distribution, or
17 * online at http://secondlife.com/developers/opensource/gplv2
18 *
19 * There are special exceptions to the terms and conditions of the GPL as
20 * it is applied to this Source Code. View the full text of the exception
21 * in the file doc/FLOSS-exception.txt in this software distribution, or
22 * online at http://secondlife.com/developers/opensource/flossexception
23 *
24 * By copying, modifying or distributing this software, you acknowledge
25 * that you have read and understood your obligations described above,
26 * and agree to abide by those obligations.
27 *
28 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
29 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
30 * COMPLETENESS OR PERFORMANCE.
31 * $/LicenseInfo$
32 */
33
34#ifdef LL_STANDALONE
35# include <ares_dns.h>
36#else
37# include <ares/ares_dns.h>
38#endif
39
40#include "apr-1/apr_portable.h"
41#include "apr-1/apr_network_io.h"
42#include "apr-1/apr_poll.h"
43
44#include "linden_common.h"
45#include "llapr.h"
46#include "llares.h"
47
48#if defined(LL_WINDOWS)
49# define ns_c_in 1
50# define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */
51# define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */
52# define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */
53#else
54# include <arpa/nameser.h>
55#endif
56
57LLAres::HostResponder::~HostResponder()
58{
59}
60
61void LLAres::HostResponder::hostResult(const hostent *ent)
62{
63 llinfos << "LLAres::HostResponder::hostResult not implemented" << llendl;
64}
65
66void LLAres::HostResponder::hostError(int code)
67{
68 llinfos << "LLAres::HostResponder::hostError " << code << ": "
69 << LLAres::strerror(code) << llendl;
70}
71
72LLAres::NameInfoResponder::~NameInfoResponder()
73{
74}
75
76void LLAres::NameInfoResponder::nameInfoResult(const char *node,
77 const char *service)
78{
79 llinfos << "LLAres::NameInfoResponder::nameInfoResult not implemented"
80 << llendl;
81}
82
83void LLAres::NameInfoResponder::nameInfoError(int code)
84{
85 llinfos << "LLAres::NameInfoResponder::nameInfoError " << code << ": "
86 << LLAres::strerror(code) << llendl;
87}
88
89LLAres::QueryResponder::~QueryResponder()
90{
91}
92
93void LLAres::QueryResponder::queryResult(const char *buf, size_t len)
94{
95 llinfos << "LLAres::QueryResponder::queryResult not implemented"
96 << llendl;
97}
98
99void LLAres::QueryResponder::queryError(int code)
100{
101 llinfos << "LLAres::QueryResponder::queryError " << code << ": "
102 << LLAres::strerror(code) << llendl;
103}
104
105LLAres::LLAres()
106{
107 ares_init(&chan_);
108}
109
110LLAres::~LLAres()
111{
112 ares_destroy(chan_);
113}
114
115void LLAres::cancel()
116{
117 ares_cancel(chan_);
118}
119
120static void host_callback(void *arg, int status, struct hostent *ent)
121{
122 LLPointer<LLAres::HostResponder> *resp =
123 (LLPointer<LLAres::HostResponder> *) arg;
124
125 if (status == ARES_SUCCESS)
126 {
127 (*resp)->hostResult(ent);
128 } else {
129 (*resp)->hostError(status);
130 }
131
132 delete resp;
133}
134
135void LLAres::getHostByName(const char *name, HostResponder *resp,
136 int family)
137{
138 ares_gethostbyname(chan_, name, family, host_callback,
139 new LLPointer<LLAres::HostResponder>(resp));
140}
141
142void LLAres::getSrvRecords(const std::string &name, SrvResponder *resp)
143{
144 search(name, RES_SRV, resp);
145}
146
147void LLAres::rewriteURI(const std::string &uri, UriRewriteResponder *resp)
148{
149 llinfos << "Rewriting " << uri << llendl;
150
151 resp->mUri = LLURI(uri);
152 search("_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName(),
153 RES_SRV, resp);
154}
155
156LLQueryResponder::LLQueryResponder()
157 : LLAres::QueryResponder(),
158 mResult(ARES_ENODATA)
159{
160}
161
162int LLQueryResponder::parseRR(const char *buf, size_t len, const char *&pos,
163 LLPointer<LLDnsRecord> &r)
164{
165 std::string rrname;
166 size_t enclen;
167 int ret;
168
169 // RR name.
170
171 ret = LLAres::expandName(pos, buf, len, rrname, enclen);
172 if (ret != ARES_SUCCESS)
173 {
174 return ret;
175 }
176
177 pos += enclen;
178
179 if (pos + NS_RRFIXEDSZ > buf + len)
180 {
181 return ARES_EBADRESP;
182 }
183
184 int rrtype = DNS_RR_TYPE(pos);
185 int rrclass = DNS_RR_CLASS(pos);
186 int rrttl = DNS_RR_TTL(pos);
187 int rrlen = DNS_RR_LEN(pos);
188
189 if (rrclass != ns_c_in)
190 {
191 return ARES_EBADRESP;
192 }
193
194 pos += NS_RRFIXEDSZ;
195
196 if (pos + rrlen > buf + len)
197 {
198 return ARES_EBADRESP;
199 }
200
201 switch (rrtype)
202 {
203 case RES_A:
204 r = new LLARecord(rrname, rrttl);
205 break;
206 case RES_NS:
207 r = new LLNsRecord(rrname, rrttl);
208 break;
209 case RES_CNAME:
210 r = new LLCnameRecord(rrname, rrttl);
211 break;
212 case RES_PTR:
213 r = new LLPtrRecord(rrname, rrttl);
214 break;
215 case RES_AAAA:
216 r = new LLAaaaRecord(rrname, rrttl);
217 break;
218 case RES_SRV:
219 r = new LLSrvRecord(rrname, rrttl);
220 break;
221 default:
222 llinfos << "LLQueryResponder::parseRR got unknown RR type " << rrtype
223 << llendl;
224 return ARES_EBADRESP;
225 }
226
227 ret = r->parse(buf, len, pos, rrlen);
228
229 if (ret == ARES_SUCCESS)
230 {
231 pos += rrlen;
232 } else {
233 r = NULL;
234 }
235
236 return ret;
237}
238
239int LLQueryResponder::parseSection(const char *buf, size_t len,
240 size_t count, const char *&pos,
241 dns_rrs_t &rrs)
242{
243 int ret = ARES_SUCCESS;
244
245 for (size_t i = 0; i < count; i++)
246 {
247 LLPointer<LLDnsRecord> r;
248 ret = parseRR(buf, len, pos, r);
249 if (ret != ARES_SUCCESS)
250 {
251 break;
252 }
253 rrs.push_back(r);
254 }
255
256 return ret;
257}
258
259void LLQueryResponder::queryResult(const char *buf, size_t len)
260{
261 const char *pos = buf;
262 int qdcount = DNS_HEADER_QDCOUNT(pos);
263 int ancount = DNS_HEADER_ANCOUNT(pos);
264 int nscount = DNS_HEADER_NSCOUNT(pos);
265 int arcount = DNS_HEADER_ARCOUNT(pos);
266 int ret;
267
268 if (qdcount == 0 || ancount + nscount + arcount == 0)
269 {
270 ret = ARES_ENODATA;
271 goto bail;
272 }
273
274 pos += NS_HFIXEDSZ;
275
276 for (int i = 0; i < qdcount; i++)
277 {
278 std::string ignore;
279 size_t enclen;
280
281 ret = LLAres::expandName(pos, buf, len, i == 0 ? mQuery : ignore,
282 enclen);
283 if (ret != ARES_SUCCESS)
284 {
285 goto bail;
286 }
287
288 pos += enclen;
289
290 if (i == 0)
291 {
292 int t = DNS_QUESTION_TYPE(pos);
293 switch (t)
294 {
295 case RES_A:
296 case RES_NS:
297 case RES_CNAME:
298 case RES_PTR:
299 case RES_AAAA:
300 case RES_SRV:
301 mType = (LLResType) t;
302 break;
303 default:
304 llinfos << "Cannot grok query type " << t << llendl;
305 ret = ARES_EBADQUERY;
306 goto bail;
307 }
308 }
309
310 pos += NS_QFIXEDSZ;
311 if (pos > buf + len)
312 {
313 ret = ARES_EBADRESP;
314 goto bail;
315 }
316 }
317
318 ret = parseSection(buf, len, ancount, pos, mAnswers);
319 if (ret != ARES_SUCCESS)
320 {
321 goto bail;
322 }
323
324 ret = parseSection(buf, len, nscount, pos, mAuthorities);
325 if (ret != ARES_SUCCESS)
326 {
327 goto bail;
328 }
329
330 ret = parseSection(buf, len, arcount, pos, mAdditional);
331
332bail:
333 mResult = ret;
334 if (mResult == ARES_SUCCESS)
335 {
336 queryResult();
337 } else {
338 queryError(mResult);
339 }
340}
341
342void LLQueryResponder::queryResult()
343{
344 llinfos << "LLQueryResponder::queryResult not implemented" << llendl;
345}
346
347void LLAres::SrvResponder::queryResult()
348{
349 if (mType == RES_SRV)
350 {
351 srvResult(mAnswers);
352 } else {
353 srvError(ARES_EBADRESP);
354 }
355}
356
357void LLAres::SrvResponder::queryError(int code)
358{
359 srvError(code);
360}
361
362void LLAres::SrvResponder::srvResult(const dns_rrs_t &ents)
363{
364 llinfos << "LLAres::SrvResponder::srvResult not implemented" << llendl;
365
366 for (size_t i = 0; i < ents.size(); i++)
367 {
368 const LLSrvRecord *s = (const LLSrvRecord *) ents[i].get();
369
370 llinfos << "[" << i << "] " << s->host() << ":" << s->port()
371 << " priority " << s->priority()
372 << " weight " << s->weight()
373 << llendl;
374 }
375}
376
377void LLAres::SrvResponder::srvError(int code)
378{
379 llinfos << "LLAres::SrvResponder::srvError " << code << ": "
380 << LLAres::strerror(code) << llendl;
381}
382
383static void nameinfo_callback(void *arg, int status, char *node, char *service)
384{
385 LLPointer<LLAres::NameInfoResponder> *resp =
386 (LLPointer<LLAres::NameInfoResponder> *) arg;
387
388 if (status == ARES_SUCCESS)
389 {
390 (*resp)->nameInfoResult(node, service);
391 } else {
392 (*resp)->nameInfoError(status);
393 }
394
395 delete resp;
396}
397
398void LLAres::getNameInfo(const struct sockaddr &sa, socklen_t salen, int flags,
399 NameInfoResponder *resp)
400{
401 ares_getnameinfo(chan_, &sa, salen, flags, nameinfo_callback,
402 new LLPointer<NameInfoResponder>(resp));
403}
404
405static void search_callback(void *arg, int status, unsigned char *abuf,
406 int alen)
407{
408 LLPointer<LLAres::QueryResponder> *resp =
409 (LLPointer<LLAres::QueryResponder> *) arg;
410
411 if (status == ARES_SUCCESS)
412 {
413 (*resp)->queryResult((const char *) abuf, alen);
414 } else {
415 (*resp)->queryError(status);
416 }
417
418 delete resp;
419}
420
421void LLAres::search(const std::string &query, LLResType type,
422 QueryResponder *resp)
423{
424 ares_search(chan_, query.c_str(), ns_c_in, type, search_callback,
425 new LLPointer<QueryResponder>(resp));
426}
427
428bool LLAres::process(U64 timeout)
429{
430 if (!gAPRPoolp)
431 {
432 ll_init_apr();
433 }
434
435 int socks[ARES_GETSOCK_MAXNUM];
436 apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM];
437 apr_int32_t nsds = 0;
438 apr_status_t status;
439 apr_pool_t *pool;
440 int nactive = 0;
441 int bitmask;
442
443 bitmask = ares_getsock(chan_, socks, ARES_GETSOCK_MAXNUM);
444
445 if (bitmask == 0)
446 {
447 goto bail;
448 }
449
450 status = apr_pool_create(&pool, gAPRPoolp);
451 ll_apr_assert_status(status);
452
453 for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++)
454 {
455 if (ARES_GETSOCK_READABLE(bitmask, i))
456 {
457 aprFds[nactive].reqevents = APR_POLLIN | APR_POLLERR;
458 }
459 else if (ARES_GETSOCK_WRITABLE(bitmask, i))
460 {
461 aprFds[nactive].reqevents = APR_POLLOUT | APR_POLLERR;
462 } else {
463 continue;
464 }
465
466 apr_socket_t *aprSock = NULL;
467
468 status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], pool);
469 if (status != APR_SUCCESS)
470 {
471 ll_apr_warn_status(status);
472 goto bail_pool;
473 }
474
475 aprFds[nactive].desc.s = aprSock;
476 aprFds[nactive].desc_type = APR_POLL_SOCKET;
477 aprFds[nactive].p = pool;
478 aprFds[nactive].rtnevents = 0;
479 aprFds[nactive].client_data = &socks[i];
480
481 nactive++;
482 }
483
484 if (nactive > 0)
485 {
486 status = apr_poll(aprFds, nactive, &nsds, timeout);
487
488 if (status != APR_SUCCESS && status != APR_TIMEUP)
489 {
490 ll_apr_warn_status(status);
491 }
492
493 for (int i = 0; i < nactive; i++)
494 {
495 int evts = aprFds[i].rtnevents;
496 int ifd = (evts & (APR_POLLIN | APR_POLLERR))
497 ? *((int *) aprFds[i].client_data) : ARES_SOCKET_BAD;
498 int ofd = (evts & (APR_POLLOUT | APR_POLLERR))
499 ? *((int *) aprFds[i].client_data) : ARES_SOCKET_BAD;
500
501 ares_process_fd(chan_, ifd, ofd);
502 }
503 }
504
505bail_pool:
506 apr_pool_destroy(pool);
507
508bail:
509 return nsds > 0;
510}
511
512bool LLAres::processAll()
513{
514 bool anyProcessed = false, ret;
515
516 do {
517 timeval tv;
518
519 ret = ares_timeout(chan_, NULL, &tv) != NULL;
520
521 if (ret)
522 {
523 ret = process(tv.tv_sec * 1000000LL + tv.tv_usec);
524 anyProcessed |= ret;
525 }
526 } while (ret);
527
528 return anyProcessed;
529}
530
531int LLAres::expandName(const char *encoded, const char *abuf, size_t alen,
532 std::string &s, size_t &enclen)
533{
534 char *t;
535 int ret;
536 long e;
537
538 ret = ares_expand_name((const unsigned char *) encoded,
539 (const unsigned char *) abuf, alen, &t, &e);
540 if (ret == ARES_SUCCESS)
541 {
542 s.assign(t);
543 enclen = e;
544 ares_free_string(t);
545 }
546 return ret;
547}
548
549const char *LLAres::strerror(int code)
550{
551 return ares_strerror(code);
552}
553
554LLAres *gAres;
555
556LLAres *ll_init_ares()
557{
558 if (gAres == NULL)
559 {
560 gAres = new LLAres();
561 }
562 return gAres;
563}
564
565LLDnsRecord::LLDnsRecord(LLResType type, const std::string &name,
566 unsigned ttl)
567 : LLRefCount(),
568 mType(type),
569 mName(name),
570 mTTL(ttl)
571{
572}
573
574LLHostRecord::LLHostRecord(LLResType type, const std::string &name,
575 unsigned ttl)
576 : LLDnsRecord(type, name, ttl)
577{
578}
579
580int LLHostRecord::parse(const char *buf, size_t len, const char *pos,
581 size_t rrlen)
582{
583 int ret;
584
585 ret = LLAres::expandName(pos, buf, len, mHost);
586 if (ret != ARES_SUCCESS)
587 {
588 goto bail;
589 }
590
591 ret = ARES_SUCCESS;
592
593bail:
594 return ret;
595}
596
597LLCnameRecord::LLCnameRecord(const std::string &name, unsigned ttl)
598 : LLHostRecord(RES_CNAME, name, ttl)
599{
600}
601
602LLPtrRecord::LLPtrRecord(const std::string &name, unsigned ttl)
603 : LLHostRecord(RES_PTR, name, ttl)
604{
605}
606
607LLAddrRecord::LLAddrRecord(LLResType type, const std::string &name,
608 unsigned ttl)
609 : LLDnsRecord(type, name, ttl)
610{
611}
612
613LLARecord::LLARecord(const std::string &name, unsigned ttl)
614 : LLAddrRecord(RES_A, name, ttl)
615{
616}
617
618int LLARecord::parse(const char *buf, size_t len, const char *pos,
619 size_t rrlen)
620{
621 int ret;
622
623 if (rrlen != sizeof(mSA.sin.sin_addr.s_addr))
624 {
625 ret = ARES_EBADRESP;
626 goto bail;
627 }
628
629 memset(&mSA, 0, sizeof(mSA));
630 memcpy(&mSA.sin.sin_addr.s_addr, pos, rrlen);
631 mSA.sin.sin_family = AF_INET6;
632 mSize = sizeof(mSA.sin);
633
634 ret = ARES_SUCCESS;
635
636bail:
637 return ret;
638}
639
640LLAaaaRecord::LLAaaaRecord(const std::string &name, unsigned ttl)
641 : LLAddrRecord(RES_AAAA, name, ttl)
642{
643}
644
645int LLAaaaRecord::parse(const char *buf, size_t len, const char *pos,
646 size_t rrlen)
647{
648 int ret;
649
650 if (rrlen != sizeof(mSA.sin6.sin6_addr))
651 {
652 ret = ARES_EBADRESP;
653 goto bail;
654 }
655
656 memset(&mSA, 0, sizeof(mSA));
657 memcpy(&mSA.sin6.sin6_addr.s6_addr, pos, rrlen);
658 mSA.sin6.sin6_family = AF_INET6;
659 mSize = sizeof(mSA.sin6);
660
661 ret = ARES_SUCCESS;
662
663bail:
664 return ret;
665}
666
667LLSrvRecord::LLSrvRecord(const std::string &name, unsigned ttl)
668 : LLHostRecord(RES_SRV, name, ttl)
669{
670}
671
672int LLSrvRecord::parse(const char *buf, size_t len, const char *pos,
673 size_t rrlen)
674{
675 int ret;
676
677 if (rrlen < 6)
678 {
679 ret = ARES_EBADRESP;
680 goto bail;
681 }
682
683 memcpy(&mPriority, pos, 2);
684 memcpy(&mWeight, pos + 2, 2);
685 memcpy(&mPort, pos + 4, 2);
686
687 mPriority = ntohs(mPriority);
688 mWeight = ntohs(mWeight);
689 mPort = ntohs(mPort);
690
691 ret = LLHostRecord::parse(buf, len, pos + 6, rrlen - 6);
692
693bail:
694 return ret;
695}
696
697LLNsRecord::LLNsRecord(const std::string &name, unsigned ttl)
698 : LLHostRecord(RES_NS, name, ttl)
699{
700}
701
702void LLAres::UriRewriteResponder::queryError(int code)
703{
704 std::vector<std::string> uris;
705 uris.push_back(mUri.asString());
706 rewriteResult(uris);
707}
708
709void LLAres::UriRewriteResponder::queryResult()
710{
711 std::vector<std::string> uris;
712
713 if (mType != RES_SRV)
714 {
715 goto bail;
716 }
717
718 for (size_t i = 0; i < mAnswers.size(); i++)
719 {
720 const LLSrvRecord *r = (const LLSrvRecord *) mAnswers[i].get();
721
722 if (r->type() == RES_SRV)
723 {
724 // Check the domain in the response to ensure that it's
725 // the same as the domain in the request, so that bad guys
726 // can't forge responses that point to their own login
727 // servers with their own certificates.
728
729 // Hard-coding the domain to check here is a bit of a
730 // hack. Hoist it to an outer caller if anyone ever needs
731 // this functionality on other domains.
732
733 static const std::string domain(".lindenlab.com");
734 const std::string &host = r->host();
735
736 std::string::size_type s = host.find(domain) + domain.length();
737
738 if (s != host.length() && s != host.length() - 1)
739 {
740 continue;
741 }
742
743 LLURI uri(mUri.scheme(),
744 mUri.userName(),
745 mUri.password(),
746 r->host(),
747 mUri.defaultPort() ? r->port() : mUri.hostPort(),
748 mUri.escapedPath(),
749 mUri.escapedQuery());
750 uris.push_back(uri.asString());
751 }
752 }
753
754 if (!uris.empty())
755 {
756 goto done;
757 }
758
759bail:
760 uris.push_back(mUri.asString());
761
762done:
763 rewriteResult(uris);
764}
765
766void LLAres::UriRewriteResponder::rewriteResult(
767 const std::vector<std::string> &uris)
768{
769 llinfos << "LLAres::UriRewriteResponder::rewriteResult not implemented"
770 << llendl;
771
772 for (size_t i = 0; i < uris.size(); i++)
773 {
774 llinfos << "[" << i << "] " << uris[i] << llendl;
775 }
776}