aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon/llares.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llcommon/llares.cpp')
-rw-r--r--linden/indra/llcommon/llares.cpp805
1 files changed, 0 insertions, 805 deletions
diff --git a/linden/indra/llcommon/llares.cpp b/linden/indra/llcommon/llares.cpp
deleted file mode 100644
index 4d054e4..0000000
--- a/linden/indra/llcommon/llares.cpp
+++ /dev/null
@@ -1,805 +0,0 @@
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-2008, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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 : chan_(NULL)
107{
108 ares_init(&chan_);
109}
110
111LLAres::~LLAres()
112{
113 if (chan_)
114 ares_destroy(chan_);
115}
116
117void LLAres::cancel()
118{
119 if (chan_)
120 ares_cancel(chan_);
121}
122
123static void host_callback(void *arg, int status, struct hostent *ent)
124{
125 LLPointer<LLAres::HostResponder> *resp =
126 (LLPointer<LLAres::HostResponder> *) arg;
127
128 if (status == ARES_SUCCESS)
129 {
130 (*resp)->hostResult(ent);
131 } else {
132 (*resp)->hostError(status);
133 }
134
135 delete resp;
136}
137
138void LLAres::getHostByName(const char *name, HostResponder *resp,
139 int family)
140{
141 if (!chan_)
142 {
143 resp->hostError(ARES_EBADRESP);
144 return;
145 }
146 ares_gethostbyname(chan_, name, family, host_callback,
147 new LLPointer<LLAres::HostResponder>(resp));
148}
149
150void LLAres::getSrvRecords(const std::string &name, SrvResponder *resp)
151{
152 search(name, RES_SRV, resp);
153}
154
155void LLAres::rewriteURI(const std::string &uri, UriRewriteResponder *resp)
156{
157 LL_DEBUGS2("AppInit","Rewrite") << "Rewriting " << uri << LL_ENDL;
158
159 resp->mUri = LLURI(uri);
160 search("_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName(),
161 RES_SRV, resp);
162}
163
164LLQueryResponder::LLQueryResponder()
165 : LLAres::QueryResponder(),
166 mResult(ARES_ENODATA),
167 mType(RES_INVALID)
168{
169}
170
171int LLQueryResponder::parseRR(const char *buf, size_t len, const char *&pos,
172 LLPointer<LLDnsRecord> &r)
173{
174 std::string rrname;
175 size_t enclen;
176 int ret;
177
178 // RR name.
179
180 ret = LLAres::expandName(pos, buf, len, rrname, enclen);
181 if (ret != ARES_SUCCESS)
182 {
183 return ret;
184 }
185
186 pos += enclen;
187
188 if (pos + NS_RRFIXEDSZ > buf + len)
189 {
190 return ARES_EBADRESP;
191 }
192
193 int rrtype = DNS_RR_TYPE(pos);
194 int rrclass = DNS_RR_CLASS(pos);
195 int rrttl = DNS_RR_TTL(pos);
196 int rrlen = DNS_RR_LEN(pos);
197
198 if (rrclass != ns_c_in)
199 {
200 return ARES_EBADRESP;
201 }
202
203 pos += NS_RRFIXEDSZ;
204
205 if (pos + rrlen > buf + len)
206 {
207 return ARES_EBADRESP;
208 }
209
210 switch (rrtype)
211 {
212 case RES_A:
213 r = new LLARecord(rrname, rrttl);
214 break;
215 case RES_NS:
216 r = new LLNsRecord(rrname, rrttl);
217 break;
218 case RES_CNAME:
219 r = new LLCnameRecord(rrname, rrttl);
220 break;
221 case RES_PTR:
222 r = new LLPtrRecord(rrname, rrttl);
223 break;
224 case RES_AAAA:
225 r = new LLAaaaRecord(rrname, rrttl);
226 break;
227 case RES_SRV:
228 r = new LLSrvRecord(rrname, rrttl);
229 break;
230 default:
231 llinfos << "LLQueryResponder::parseRR got unknown RR type " << rrtype
232 << llendl;
233 return ARES_EBADRESP;
234 }
235
236 ret = r->parse(buf, len, pos, rrlen);
237
238 if (ret == ARES_SUCCESS)
239 {
240 pos += rrlen;
241 } else {
242 r = NULL;
243 }
244
245 return ret;
246}
247
248int LLQueryResponder::parseSection(const char *buf, size_t len,
249 size_t count, const char *&pos,
250 dns_rrs_t &rrs)
251{
252 int ret = ARES_SUCCESS;
253
254 for (size_t i = 0; i < count; i++)
255 {
256 LLPointer<LLDnsRecord> r;
257 ret = parseRR(buf, len, pos, r);
258 if (ret != ARES_SUCCESS)
259 {
260 break;
261 }
262 rrs.push_back(r);
263 }
264
265 return ret;
266}
267
268void LLQueryResponder::queryResult(const char *buf, size_t len)
269{
270 const char *pos = buf;
271 int qdcount = DNS_HEADER_QDCOUNT(pos);
272 int ancount = DNS_HEADER_ANCOUNT(pos);
273 int nscount = DNS_HEADER_NSCOUNT(pos);
274 int arcount = DNS_HEADER_ARCOUNT(pos);
275 int ret;
276
277 if (qdcount == 0 || ancount + nscount + arcount == 0)
278 {
279 ret = ARES_ENODATA;
280 goto bail;
281 }
282
283 pos += NS_HFIXEDSZ;
284
285 for (int i = 0; i < qdcount; i++)
286 {
287 std::string ignore;
288 size_t enclen;
289
290 ret = LLAres::expandName(pos, buf, len, i == 0 ? mQuery : ignore,
291 enclen);
292 if (ret != ARES_SUCCESS)
293 {
294 goto bail;
295 }
296
297 pos += enclen;
298
299 if (i == 0)
300 {
301 int t = DNS_QUESTION_TYPE(pos);
302 switch (t)
303 {
304 case RES_A:
305 case RES_NS:
306 case RES_CNAME:
307 case RES_PTR:
308 case RES_AAAA:
309 case RES_SRV:
310 mType = (LLResType) t;
311 break;
312 default:
313 llinfos << "Cannot grok query type " << t << llendl;
314 ret = ARES_EBADQUERY;
315 goto bail;
316 }
317 }
318
319 pos += NS_QFIXEDSZ;
320 if (pos > buf + len)
321 {
322 ret = ARES_EBADRESP;
323 goto bail;
324 }
325 }
326
327 ret = parseSection(buf, len, ancount, pos, mAnswers);
328 if (ret != ARES_SUCCESS)
329 {
330 goto bail;
331 }
332
333 ret = parseSection(buf, len, nscount, pos, mAuthorities);
334 if (ret != ARES_SUCCESS)
335 {
336 goto bail;
337 }
338
339 ret = parseSection(buf, len, arcount, pos, mAdditional);
340
341bail:
342 mResult = ret;
343 if (mResult == ARES_SUCCESS)
344 {
345 queryResult();
346 } else {
347 queryError(mResult);
348 }
349}
350
351void LLQueryResponder::queryResult()
352{
353 llinfos << "LLQueryResponder::queryResult not implemented" << llendl;
354}
355
356void LLAres::SrvResponder::queryResult()
357{
358 if (mType == RES_SRV)
359 {
360 srvResult(mAnswers);
361 } else {
362 srvError(ARES_EBADRESP);
363 }
364}
365
366void LLAres::SrvResponder::queryError(int code)
367{
368 srvError(code);
369}
370
371void LLAres::SrvResponder::srvResult(const dns_rrs_t &ents)
372{
373 llinfos << "LLAres::SrvResponder::srvResult not implemented" << llendl;
374
375 for (size_t i = 0; i < ents.size(); i++)
376 {
377 const LLSrvRecord *s = (const LLSrvRecord *) ents[i].get();
378
379 llinfos << "[" << i << "] " << s->host() << ":" << s->port()
380 << " priority " << s->priority()
381 << " weight " << s->weight()
382 << llendl;
383 }
384}
385
386void LLAres::SrvResponder::srvError(int code)
387{
388 llinfos << "LLAres::SrvResponder::srvError " << code << ": "
389 << LLAres::strerror(code) << llendl;
390}
391
392static void nameinfo_callback(void *arg, int status, char *node, char *service)
393{
394 LLPointer<LLAres::NameInfoResponder> *resp =
395 (LLPointer<LLAres::NameInfoResponder> *) arg;
396
397 if (status == ARES_SUCCESS)
398 {
399 (*resp)->nameInfoResult(node, service);
400 } else {
401 (*resp)->nameInfoError(status);
402 }
403
404 delete resp;
405}
406
407void LLAres::getNameInfo(const struct sockaddr &sa, socklen_t salen, int flags,
408 NameInfoResponder *resp)
409{
410 if (!chan_)
411 {
412 resp->nameInfoError(ARES_EBADRESP);
413 return;
414 }
415 ares_getnameinfo(chan_, &sa, salen, flags, nameinfo_callback,
416 new LLPointer<NameInfoResponder>(resp));
417}
418
419static void search_callback(void *arg, int status, unsigned char *abuf,
420 int alen)
421{
422 LLPointer<LLAres::QueryResponder> *resp =
423 (LLPointer<LLAres::QueryResponder> *) arg;
424
425 if (status == ARES_SUCCESS)
426 {
427 (*resp)->queryResult((const char *) abuf, alen);
428 } else {
429 (*resp)->queryError(status);
430 }
431
432 delete resp;
433}
434
435void LLAres::search(const std::string &query, LLResType type,
436 QueryResponder *resp)
437{
438 if (!chan_)
439 {
440 resp->queryError(ARES_EBADRESP);
441 return;
442 }
443 ares_search(chan_, query.c_str(), ns_c_in, type, search_callback,
444 new LLPointer<QueryResponder>(resp));
445}
446
447bool LLAres::process(U64 timeout)
448{
449 if (!gAPRPoolp)
450 {
451 ll_init_apr();
452 }
453
454 int socks[ARES_GETSOCK_MAXNUM];
455 apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM];
456 apr_int32_t nsds = 0;
457 apr_status_t status;
458 apr_pool_t *pool;
459 int nactive = 0;
460 int bitmask;
461
462 if (!chan_)
463 {
464 goto bail;
465 }
466
467 bitmask = ares_getsock(chan_, socks, ARES_GETSOCK_MAXNUM);
468
469 if (bitmask == 0)
470 {
471 goto bail;
472 }
473
474 status = apr_pool_create(&pool, gAPRPoolp);
475 ll_apr_assert_status(status);
476
477 for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++)
478 {
479 if (ARES_GETSOCK_READABLE(bitmask, i))
480 {
481 aprFds[nactive].reqevents = APR_POLLIN | APR_POLLERR;
482 }
483 else if (ARES_GETSOCK_WRITABLE(bitmask, i))
484 {
485 aprFds[nactive].reqevents = APR_POLLOUT | APR_POLLERR;
486 } else {
487 continue;
488 }
489
490 apr_socket_t *aprSock = NULL;
491
492 status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], pool);
493 if (status != APR_SUCCESS)
494 {
495 ll_apr_warn_status(status);
496 goto bail_pool;
497 }
498
499 aprFds[nactive].desc.s = aprSock;
500 aprFds[nactive].desc_type = APR_POLL_SOCKET;
501 aprFds[nactive].p = pool;
502 aprFds[nactive].rtnevents = 0;
503 aprFds[nactive].client_data = &socks[i];
504
505 nactive++;
506 }
507
508 if (nactive > 0)
509 {
510 status = apr_poll(aprFds, nactive, &nsds, timeout);
511
512 if (status != APR_SUCCESS && status != APR_TIMEUP)
513 {
514 ll_apr_warn_status(status);
515 }
516
517 for (int i = 0; i < nactive; i++)
518 {
519 int evts = aprFds[i].rtnevents;
520 int ifd = (evts & (APR_POLLIN | APR_POLLERR))
521 ? *((int *) aprFds[i].client_data) : ARES_SOCKET_BAD;
522 int ofd = (evts & (APR_POLLOUT | APR_POLLERR))
523 ? *((int *) aprFds[i].client_data) : ARES_SOCKET_BAD;
524
525 ares_process_fd(chan_, ifd, ofd);
526 }
527 }
528
529bail_pool:
530 apr_pool_destroy(pool);
531
532bail:
533 return nsds > 0;
534}
535
536bool LLAres::processAll()
537{
538 if (!chan_)
539 {
540 return false;
541 }
542
543 bool anyProcessed = false, ret;
544
545 do {
546 timeval tv;
547
548 ret = ares_timeout(chan_, NULL, &tv) != NULL;
549
550 if (ret)
551 {
552 ret = process(tv.tv_sec * 1000000LL + tv.tv_usec);
553 anyProcessed |= ret;
554 }
555 } while (ret);
556
557 return anyProcessed;
558}
559
560int LLAres::expandName(const char *encoded, const char *abuf, size_t alen,
561 std::string &s, size_t &enclen)
562{
563 char *t;
564 int ret;
565 long e;
566
567 ret = ares_expand_name((const unsigned char *) encoded,
568 (const unsigned char *) abuf, alen, &t, &e);
569 if (ret == ARES_SUCCESS)
570 {
571 s.assign(t);
572 enclen = e;
573 ares_free_string(t);
574 }
575 return ret;
576}
577
578const char *LLAres::strerror(int code)
579{
580 return ares_strerror(code);
581}
582
583LLAres *gAres;
584
585LLAres *ll_init_ares()
586{
587 if (gAres == NULL)
588 {
589 gAres = new LLAres();
590 }
591 return gAres;
592}
593
594LLDnsRecord::LLDnsRecord(LLResType type, const std::string &name,
595 unsigned ttl)
596 : LLRefCount(),
597 mType(type),
598 mName(name),
599 mTTL(ttl)
600{
601}
602
603LLHostRecord::LLHostRecord(LLResType type, const std::string &name,
604 unsigned ttl)
605 : LLDnsRecord(type, name, ttl)
606{
607}
608
609int LLHostRecord::parse(const char *buf, size_t len, const char *pos,
610 size_t rrlen)
611{
612 int ret;
613
614 ret = LLAres::expandName(pos, buf, len, mHost);
615 if (ret != ARES_SUCCESS)
616 {
617 goto bail;
618 }
619
620 ret = ARES_SUCCESS;
621
622bail:
623 return ret;
624}
625
626LLCnameRecord::LLCnameRecord(const std::string &name, unsigned ttl)
627 : LLHostRecord(RES_CNAME, name, ttl)
628{
629}
630
631LLPtrRecord::LLPtrRecord(const std::string &name, unsigned ttl)
632 : LLHostRecord(RES_PTR, name, ttl)
633{
634}
635
636LLAddrRecord::LLAddrRecord(LLResType type, const std::string &name,
637 unsigned ttl)
638 : LLDnsRecord(type, name, ttl)
639{
640}
641
642LLARecord::LLARecord(const std::string &name, unsigned ttl)
643 : LLAddrRecord(RES_A, name, ttl)
644{
645}
646
647int LLARecord::parse(const char *buf, size_t len, const char *pos,
648 size_t rrlen)
649{
650 int ret;
651
652 if (rrlen != sizeof(mSA.sin.sin_addr.s_addr))
653 {
654 ret = ARES_EBADRESP;
655 goto bail;
656 }
657
658 memset(&mSA, 0, sizeof(mSA));
659 memcpy(&mSA.sin.sin_addr.s_addr, pos, rrlen);
660 mSA.sin.sin_family = AF_INET6;
661 mSize = sizeof(mSA.sin);
662
663 ret = ARES_SUCCESS;
664
665bail:
666 return ret;
667}
668
669LLAaaaRecord::LLAaaaRecord(const std::string &name, unsigned ttl)
670 : LLAddrRecord(RES_AAAA, name, ttl)
671{
672}
673
674int LLAaaaRecord::parse(const char *buf, size_t len, const char *pos,
675 size_t rrlen)
676{
677 int ret;
678
679 if (rrlen != sizeof(mSA.sin6.sin6_addr))
680 {
681 ret = ARES_EBADRESP;
682 goto bail;
683 }
684
685 memset(&mSA, 0, sizeof(mSA));
686 memcpy(&mSA.sin6.sin6_addr.s6_addr, pos, rrlen);
687 mSA.sin6.sin6_family = AF_INET6;
688 mSize = sizeof(mSA.sin6);
689
690 ret = ARES_SUCCESS;
691
692bail:
693 return ret;
694}
695
696LLSrvRecord::LLSrvRecord(const std::string &name, unsigned ttl)
697 : LLHostRecord(RES_SRV, name, ttl)
698{
699}
700
701int LLSrvRecord::parse(const char *buf, size_t len, const char *pos,
702 size_t rrlen)
703{
704 int ret;
705
706 if (rrlen < 6)
707 {
708 ret = ARES_EBADRESP;
709 goto bail;
710 }
711
712 memcpy(&mPriority, pos, 2);
713 memcpy(&mWeight, pos + 2, 2);
714 memcpy(&mPort, pos + 4, 2);
715
716 mPriority = ntohs(mPriority);
717 mWeight = ntohs(mWeight);
718 mPort = ntohs(mPort);
719
720 ret = LLHostRecord::parse(buf, len, pos + 6, rrlen - 6);
721
722bail:
723 return ret;
724}
725
726LLNsRecord::LLNsRecord(const std::string &name, unsigned ttl)
727 : LLHostRecord(RES_NS, name, ttl)
728{
729}
730
731void LLAres::UriRewriteResponder::queryError(int code)
732{
733 std::vector<std::string> uris;
734 uris.push_back(mUri.asString());
735 rewriteResult(uris);
736}
737
738void LLAres::UriRewriteResponder::queryResult()
739{
740 std::vector<std::string> uris;
741
742 if (mType != RES_SRV)
743 {
744 goto bail;
745 }
746
747 for (size_t i = 0; i < mAnswers.size(); i++)
748 {
749 const LLSrvRecord *r = (const LLSrvRecord *) mAnswers[i].get();
750
751 if (r->type() == RES_SRV)
752 {
753 // Check the domain in the response to ensure that it's
754 // the same as the domain in the request, so that bad guys
755 // can't forge responses that point to their own login
756 // servers with their own certificates.
757
758 // Hard-coding the domain to check here is a bit of a
759 // hack. Hoist it to an outer caller if anyone ever needs
760 // this functionality on other domains.
761
762 static const std::string domain(".lindenlab.com");
763 const std::string &host = r->host();
764
765 std::string::size_type s = host.find(domain) + domain.length();
766
767 if (s != host.length() && s != host.length() - 1)
768 {
769 continue;
770 }
771
772 LLURI uri(mUri.scheme(),
773 mUri.userName(),
774 mUri.password(),
775 r->host(),
776 mUri.defaultPort() ? r->port() : mUri.hostPort(),
777 mUri.escapedPath(),
778 mUri.escapedQuery());
779 uris.push_back(uri.asString());
780 }
781 }
782
783 if (!uris.empty())
784 {
785 goto done;
786 }
787
788bail:
789 uris.push_back(mUri.asString());
790
791done:
792 rewriteResult(uris);
793}
794
795void LLAres::UriRewriteResponder::rewriteResult(
796 const std::vector<std::string> &uris)
797{
798 llinfos << "LLAres::UriRewriteResponder::rewriteResult not implemented"
799 << llendl;
800
801 for (size_t i = 0; i < uris.size(); i++)
802 {
803 llinfos << "[" << i << "] " << uris[i] << llendl;
804 }
805}