PageRenderTime 105ms CodeModel.GetById 11ms app.highlight 89ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llmessage/llares.cpp

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