llares.cpp

Go to the documentation of this file.
00001 
00034 #ifdef LL_STANDALONE
00035 # include <ares_dns.h>
00036 #else
00037 # include <ares/ares_dns.h>
00038 #endif
00039 
00040 #include "apr-1/apr_portable.h"
00041 #include "apr-1/apr_network_io.h"
00042 #include "apr-1/apr_poll.h"
00043 
00044 #include "linden_common.h"
00045 #include "llapr.h"
00046 #include "llares.h"
00047 
00048 #if defined(LL_WINDOWS)
00049 # define ns_c_in 1
00050 # define NS_HFIXEDSZ     12      /* #/bytes of fixed data in header */
00051 # define NS_QFIXEDSZ     4       /* #/bytes of fixed data in query */
00052 # define NS_RRFIXEDSZ    10      /* #/bytes of fixed data in r record */
00053 #else
00054 # include <arpa/nameser.h>
00055 #endif
00056 
00057 LLAres::HostResponder::~HostResponder()
00058 {
00059 }
00060 
00061 void LLAres::HostResponder::hostResult(const hostent *ent)
00062 {
00063         llinfos << "LLAres::HostResponder::hostResult not implemented" << llendl;
00064 }
00065 
00066 void LLAres::HostResponder::hostError(int code)
00067 {
00068         llinfos << "LLAres::HostResponder::hostError " << code << ": "
00069                         << LLAres::strerror(code) << llendl;
00070 }
00071 
00072 LLAres::NameInfoResponder::~NameInfoResponder()
00073 {
00074 }
00075 
00076 void LLAres::NameInfoResponder::nameInfoResult(const char *node,
00077                                                                                            const char *service)
00078 {
00079         llinfos << "LLAres::NameInfoResponder::nameInfoResult not implemented"
00080                         << llendl;
00081 }
00082 
00083 void LLAres::NameInfoResponder::nameInfoError(int code)
00084 {
00085         llinfos << "LLAres::NameInfoResponder::nameInfoError " << code << ": "
00086                         << LLAres::strerror(code) << llendl;
00087 }
00088 
00089 LLAres::QueryResponder::~QueryResponder()
00090 {
00091 }
00092 
00093 void LLAres::QueryResponder::queryResult(const char *buf, size_t len)
00094 {
00095         llinfos << "LLAres::QueryResponder::queryResult not implemented"
00096                         << llendl;
00097 }
00098 
00099 void LLAres::QueryResponder::queryError(int code)
00100 {
00101         llinfos << "LLAres::QueryResponder::queryError " << code << ": "
00102                         << LLAres::strerror(code) << llendl;
00103 }
00104 
00105 LLAres::LLAres()
00106         : chan_(NULL)
00107 {
00108         ares_init(&chan_);
00109 }
00110 
00111 LLAres::~LLAres()
00112 {
00113         if (chan_)
00114                 ares_destroy(chan_);
00115 }
00116 
00117 void LLAres::cancel()
00118 {
00119         if (chan_)
00120                 ares_cancel(chan_);
00121 }
00122 
00123 static void host_callback(void *arg, int status, struct hostent *ent)
00124 {
00125         LLPointer<LLAres::HostResponder> *resp =
00126                 (LLPointer<LLAres::HostResponder> *) arg;
00127 
00128         if (status == ARES_SUCCESS)
00129         {
00130                 (*resp)->hostResult(ent);
00131         } else {
00132                 (*resp)->hostError(status);
00133         }
00134 
00135         delete resp;
00136 }
00137 
00138 void LLAres::getHostByName(const char *name, HostResponder *resp,
00139                                                    int family)
00140 {
00141         if (!chan_)
00142         {
00143                 resp->hostError(ARES_EBADRESP);
00144                 return;
00145         }
00146         ares_gethostbyname(chan_, name, family, host_callback,
00147                                            new LLPointer<LLAres::HostResponder>(resp));
00148 }
00149         
00150 void LLAres::getSrvRecords(const std::string &name, SrvResponder *resp)
00151 {
00152         search(name, RES_SRV, resp);
00153 }
00154         
00155 void LLAres::rewriteURI(const std::string &uri, UriRewriteResponder *resp)
00156 {
00157         LL_DEBUGS2("AppInit","Rewrite") << "Rewriting " << uri << LL_ENDL;
00158 
00159         resp->mUri = LLURI(uri);
00160         search("_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName(),
00161                    RES_SRV, resp);
00162 }
00163 
00164 LLQueryResponder::LLQueryResponder()
00165         : LLAres::QueryResponder(),
00166           mResult(ARES_ENODATA),
00167           mType(RES_INVALID)
00168 {
00169 }
00170 
00171 int LLQueryResponder::parseRR(const char *buf, size_t len, const char *&pos,
00172                                                           LLPointer<LLDnsRecord> &r)
00173 {
00174         std::string rrname;
00175         size_t enclen;
00176         int ret;
00177 
00178         // RR name.
00179 
00180         ret = LLAres::expandName(pos, buf, len, rrname, enclen);
00181         if (ret != ARES_SUCCESS)
00182         {
00183                 return ret;
00184         }
00185                 
00186         pos += enclen;
00187 
00188         if (pos + NS_RRFIXEDSZ > buf + len)
00189         {
00190                 return ARES_EBADRESP;
00191         }
00192 
00193         int rrtype = DNS_RR_TYPE(pos);
00194         int rrclass = DNS_RR_CLASS(pos);
00195         int rrttl = DNS_RR_TTL(pos);
00196         int rrlen = DNS_RR_LEN(pos);
00197                 
00198         if (rrclass != ns_c_in)
00199         {
00200                 return ARES_EBADRESP;
00201         }
00202 
00203         pos += NS_RRFIXEDSZ;
00204 
00205         if (pos + rrlen > buf + len)
00206         {
00207                 return ARES_EBADRESP;
00208         }
00209 
00210         switch (rrtype)
00211         {
00212         case RES_A:
00213                 r = new LLARecord(rrname, rrttl);
00214                 break;
00215         case RES_NS:
00216                 r = new LLNsRecord(rrname, rrttl);
00217                 break;
00218         case RES_CNAME:
00219                 r = new LLCnameRecord(rrname, rrttl);
00220                 break;
00221         case RES_PTR:
00222                 r = new LLPtrRecord(rrname, rrttl);
00223                 break;
00224         case RES_AAAA:
00225                 r = new LLAaaaRecord(rrname, rrttl);
00226                 break;
00227         case RES_SRV:
00228                 r = new LLSrvRecord(rrname, rrttl);
00229                 break;
00230         default:
00231                 llinfos << "LLQueryResponder::parseRR got unknown RR type " << rrtype
00232                                 << llendl;
00233                 return ARES_EBADRESP;
00234         }
00235 
00236         ret = r->parse(buf, len, pos, rrlen);
00237 
00238         if (ret == ARES_SUCCESS)
00239         {
00240                 pos += rrlen;
00241         } else {
00242                 r = NULL;
00243         }
00244                 
00245         return ret;
00246 }
00247 
00248 int LLQueryResponder::parseSection(const char *buf, size_t len,
00249                                                                    size_t count, const char *&pos,
00250                                                                    dns_rrs_t &rrs)
00251 {
00252         int ret = ARES_SUCCESS;
00253         
00254         for (size_t i = 0; i < count; i++)
00255         {
00256                 LLPointer<LLDnsRecord> r;
00257                 ret = parseRR(buf, len, pos, r);
00258                 if (ret != ARES_SUCCESS)
00259                 {
00260                         break;
00261                 }
00262                 rrs.push_back(r);
00263         }
00264 
00265         return ret;
00266 }
00267 
00268 void LLQueryResponder::queryResult(const char *buf, size_t len)
00269 {
00270         const char *pos = buf;
00271         int qdcount = DNS_HEADER_QDCOUNT(pos);
00272         int ancount = DNS_HEADER_ANCOUNT(pos);
00273         int nscount = DNS_HEADER_NSCOUNT(pos);
00274         int arcount = DNS_HEADER_ARCOUNT(pos);
00275         int ret;
00276 
00277         if (qdcount == 0 || ancount + nscount + arcount == 0)
00278         {
00279                 ret = ARES_ENODATA;
00280                 goto bail;
00281         }
00282 
00283         pos += NS_HFIXEDSZ;
00284 
00285         for (int i = 0; i < qdcount; i++)
00286         {
00287                 std::string ignore;
00288                 size_t enclen;
00289 
00290                 ret = LLAres::expandName(pos, buf, len, i == 0 ? mQuery : ignore,
00291                                                                  enclen);
00292                 if (ret != ARES_SUCCESS)
00293                 {
00294                         goto bail;
00295                 }
00296 
00297                 pos += enclen;
00298 
00299                 if (i == 0)
00300                 {
00301                         int t = DNS_QUESTION_TYPE(pos);
00302                         switch (t)
00303                         {
00304                         case RES_A:
00305                         case RES_NS:
00306                         case RES_CNAME:
00307                         case RES_PTR:
00308                         case RES_AAAA:
00309                         case RES_SRV:
00310                                 mType = (LLResType) t;
00311                                 break;
00312                         default:
00313                                 llinfos << "Cannot grok query type " << t << llendl;
00314                                 ret = ARES_EBADQUERY;
00315                                 goto bail;
00316                         }
00317                 }
00318 
00319                 pos += NS_QFIXEDSZ;
00320                 if (pos > buf + len)
00321                 {
00322                         ret = ARES_EBADRESP;
00323                         goto bail;
00324                 }
00325         }
00326         
00327         ret = parseSection(buf, len, ancount, pos, mAnswers);
00328         if (ret != ARES_SUCCESS)
00329         {
00330                 goto bail;
00331         }
00332 
00333         ret = parseSection(buf, len, nscount, pos, mAuthorities);
00334         if (ret != ARES_SUCCESS)
00335         {
00336                 goto bail;
00337         }
00338 
00339         ret = parseSection(buf, len, arcount, pos, mAdditional);
00340 
00341 bail:
00342         mResult = ret;
00343         if (mResult == ARES_SUCCESS)
00344         {
00345                 queryResult();
00346         } else {
00347                 queryError(mResult);
00348         }
00349 }
00350 
00351 void LLQueryResponder::queryResult()
00352 {
00353         llinfos << "LLQueryResponder::queryResult not implemented" << llendl;
00354 }
00355 
00356 void LLAres::SrvResponder::queryResult()
00357 {
00358         if (mType == RES_SRV)
00359         {
00360                 srvResult(mAnswers);
00361         } else {
00362                 srvError(ARES_EBADRESP);
00363         }
00364 }
00365 
00366 void LLAres::SrvResponder::queryError(int code)
00367 {
00368         srvError(code);
00369 }
00370 
00371 void LLAres::SrvResponder::srvResult(const dns_rrs_t &ents)
00372 {
00373         llinfos << "LLAres::SrvResponder::srvResult not implemented" << llendl;
00374 
00375         for (size_t i = 0; i < ents.size(); i++)
00376         {
00377                 const LLSrvRecord *s = (const LLSrvRecord *) ents[i].get();
00378 
00379                 llinfos << "[" << i << "] " << s->host() << ":" << s->port()
00380                                 << " priority " << s->priority()
00381                                 << " weight " << s->weight()
00382                                 << llendl;
00383         }
00384 }
00385 
00386 void LLAres::SrvResponder::srvError(int code)
00387 {
00388         llinfos << "LLAres::SrvResponder::srvError " << code << ": "
00389                         << LLAres::strerror(code) << llendl;
00390 }
00391 
00392 static void nameinfo_callback(void *arg, int status, char *node, char *service)
00393 {
00394         LLPointer<LLAres::NameInfoResponder> *resp =
00395                 (LLPointer<LLAres::NameInfoResponder> *) arg;
00396 
00397         if (status == ARES_SUCCESS)
00398         {
00399                 (*resp)->nameInfoResult(node, service);
00400         } else {
00401                 (*resp)->nameInfoError(status);
00402         }
00403 
00404         delete resp;
00405 }
00406 
00407 void LLAres::getNameInfo(const struct sockaddr &sa, socklen_t salen, int flags,
00408                                                  NameInfoResponder *resp)
00409 {
00410         if (!chan_)
00411         {
00412                 resp->nameInfoError(ARES_EBADRESP);
00413                 return;
00414         }
00415         ares_getnameinfo(chan_, &sa, salen, flags, nameinfo_callback,
00416                                          new LLPointer<NameInfoResponder>(resp));
00417 }
00418 
00419 static void search_callback(void *arg, int status, unsigned char *abuf,
00420                                                         int alen)
00421 {
00422         LLPointer<LLAres::QueryResponder> *resp =
00423                 (LLPointer<LLAres::QueryResponder> *) arg;
00424 
00425         if (status == ARES_SUCCESS)
00426         {
00427                 (*resp)->queryResult((const char *) abuf, alen);
00428         } else {
00429                 (*resp)->queryError(status);
00430         }
00431 
00432         delete resp;
00433 }
00434 
00435 void LLAres::search(const std::string &query, LLResType type,
00436                                         QueryResponder *resp)
00437 {
00438         if (!chan_)
00439         {
00440                 resp->queryError(ARES_EBADRESP);
00441                 return;
00442         }
00443         ares_search(chan_, query.c_str(), ns_c_in, type, search_callback,
00444                                 new LLPointer<QueryResponder>(resp));
00445 }
00446 
00447 bool LLAres::process(U64 timeout)
00448 {
00449         if (!gAPRPoolp)
00450         {
00451                 ll_init_apr();
00452         }
00453 
00454         int socks[ARES_GETSOCK_MAXNUM];
00455         apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM];
00456         apr_int32_t nsds = 0;
00457         apr_status_t status;
00458         apr_pool_t *pool;
00459         int nactive = 0;
00460         int bitmask;
00461 
00462         if (!chan_)
00463         {
00464                 goto bail;
00465         }
00466 
00467         bitmask = ares_getsock(chan_, socks, ARES_GETSOCK_MAXNUM);
00468 
00469         if (bitmask == 0)
00470         {
00471                 goto bail;
00472         }
00473 
00474         status = apr_pool_create(&pool, gAPRPoolp);
00475         ll_apr_assert_status(status);
00476 
00477         for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++)
00478         {
00479                 if (ARES_GETSOCK_READABLE(bitmask, i))
00480                 {
00481                         aprFds[nactive].reqevents = APR_POLLIN | APR_POLLERR;
00482                 }
00483                 else if (ARES_GETSOCK_WRITABLE(bitmask, i))
00484                 {
00485                         aprFds[nactive].reqevents = APR_POLLOUT | APR_POLLERR;
00486                 } else {
00487                         continue;
00488                 }
00489 
00490                 apr_socket_t *aprSock = NULL;
00491 
00492                 status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], pool);
00493                 if (status != APR_SUCCESS)
00494                 {
00495                         ll_apr_warn_status(status);
00496                         goto bail_pool;
00497                 }
00498 
00499                 aprFds[nactive].desc.s = aprSock;
00500                 aprFds[nactive].desc_type = APR_POLL_SOCKET;
00501                 aprFds[nactive].p = pool;
00502                 aprFds[nactive].rtnevents = 0;
00503                 aprFds[nactive].client_data = &socks[i];
00504 
00505                 nactive++;
00506         }
00507 
00508         if (nactive > 0)
00509         {
00510                 status = apr_poll(aprFds, nactive, &nsds, timeout);
00511 
00512                 if (status != APR_SUCCESS && status != APR_TIMEUP)
00513                 {
00514                         ll_apr_warn_status(status);
00515                 }
00516 
00517                 for (int i = 0; i < nactive; i++)
00518                 {
00519                         int evts = aprFds[i].rtnevents;
00520                         int ifd = (evts & (APR_POLLIN | APR_POLLERR))
00521                                 ? *((int *) aprFds[i].client_data) : ARES_SOCKET_BAD;
00522                         int ofd = (evts & (APR_POLLOUT | APR_POLLERR))
00523                                 ? *((int *) aprFds[i].client_data) : ARES_SOCKET_BAD;
00524                                         
00525                         ares_process_fd(chan_, ifd, ofd);
00526                 }
00527         }
00528 
00529 bail_pool:
00530         apr_pool_destroy(pool);
00531 
00532 bail:
00533         return nsds > 0;
00534 }
00535 
00536 bool LLAres::processAll()
00537 {
00538         if (!chan_)
00539         {
00540                 return false;
00541         }
00542         
00543         bool anyProcessed = false, ret;
00544 
00545         do {
00546                 timeval tv;
00547 
00548                 ret = ares_timeout(chan_, NULL, &tv) != NULL;
00549 
00550                 if (ret)
00551                 {
00552                         ret = process(tv.tv_sec * 1000000LL + tv.tv_usec);
00553                         anyProcessed |= ret;
00554                 }
00555         } while (ret);
00556 
00557         return anyProcessed;
00558 }
00559 
00560 int LLAres::expandName(const char *encoded, const char *abuf, size_t alen,
00561                                            std::string &s, size_t &enclen)
00562 {
00563         char *t;
00564         int ret;
00565         long e;
00566         
00567         ret = ares_expand_name((const unsigned char *) encoded,
00568                                                    (const unsigned char *) abuf, alen, &t, &e);
00569         if (ret == ARES_SUCCESS)
00570         {
00571                 s.assign(t);
00572                 enclen = e;
00573                 ares_free_string(t);
00574         }
00575         return ret;
00576 }
00577 
00578 const char *LLAres::strerror(int code)
00579 {
00580         return ares_strerror(code);
00581 }
00582 
00583 LLAres *gAres;
00584 
00585 LLAres *ll_init_ares()
00586 {
00587         if (gAres == NULL)
00588         {
00589                 gAres = new LLAres();
00590         }
00591         return gAres;
00592 }
00593 
00594 LLDnsRecord::LLDnsRecord(LLResType type, const std::string &name,
00595                                                  unsigned ttl)
00596         : LLRefCount(),
00597           mType(type),
00598           mName(name),
00599           mTTL(ttl)
00600 {
00601 }
00602 
00603 LLHostRecord::LLHostRecord(LLResType type, const std::string &name,
00604                                                    unsigned ttl)
00605         : LLDnsRecord(type, name, ttl)
00606 {
00607 }
00608 
00609 int LLHostRecord::parse(const char *buf, size_t len, const char *pos,
00610                                                 size_t rrlen)
00611 {
00612         int ret;
00613 
00614         ret = LLAres::expandName(pos, buf, len, mHost);
00615         if (ret != ARES_SUCCESS)
00616         {
00617                 goto bail;
00618         }
00619         
00620         ret = ARES_SUCCESS;
00621 
00622 bail:
00623         return ret;
00624 }
00625 
00626 LLCnameRecord::LLCnameRecord(const std::string &name, unsigned ttl)
00627         : LLHostRecord(RES_CNAME, name, ttl)
00628 {
00629 }
00630 
00631 LLPtrRecord::LLPtrRecord(const std::string &name, unsigned ttl)
00632         : LLHostRecord(RES_PTR, name, ttl)
00633 {
00634 }
00635 
00636 LLAddrRecord::LLAddrRecord(LLResType type, const std::string &name,
00637                                                    unsigned ttl)
00638         : LLDnsRecord(type, name, ttl)
00639 {
00640 }
00641 
00642 LLARecord::LLARecord(const std::string &name, unsigned ttl)
00643         : LLAddrRecord(RES_A, name, ttl)
00644 {
00645 }
00646 
00647 int LLARecord::parse(const char *buf, size_t len, const char *pos,
00648                                          size_t rrlen)
00649 {
00650         int ret;
00651 
00652         if (rrlen != sizeof(mSA.sin.sin_addr.s_addr))
00653         {
00654                 ret = ARES_EBADRESP;
00655                 goto bail;
00656         }
00657         
00658         memset(&mSA, 0, sizeof(mSA));
00659         memcpy(&mSA.sin.sin_addr.s_addr, pos, rrlen);
00660         mSA.sin.sin_family = AF_INET6;
00661         mSize = sizeof(mSA.sin);
00662         
00663         ret = ARES_SUCCESS;
00664 
00665 bail:
00666         return ret;
00667 }
00668 
00669 LLAaaaRecord::LLAaaaRecord(const std::string &name, unsigned ttl)
00670         : LLAddrRecord(RES_AAAA, name, ttl)
00671 {
00672 }
00673 
00674 int LLAaaaRecord::parse(const char *buf, size_t len, const char *pos,
00675                                                 size_t rrlen)
00676 {
00677         int ret;
00678 
00679         if (rrlen != sizeof(mSA.sin6.sin6_addr))
00680         {
00681                 ret = ARES_EBADRESP;
00682                 goto bail;
00683         }
00684         
00685         memset(&mSA, 0, sizeof(mSA));
00686         memcpy(&mSA.sin6.sin6_addr.s6_addr, pos, rrlen);
00687         mSA.sin6.sin6_family = AF_INET6;
00688         mSize = sizeof(mSA.sin6);
00689         
00690         ret = ARES_SUCCESS;
00691 
00692 bail:
00693         return ret;
00694 }
00695 
00696 LLSrvRecord::LLSrvRecord(const std::string &name, unsigned ttl)
00697         : LLHostRecord(RES_SRV, name, ttl)
00698 {
00699 }
00700 
00701 int LLSrvRecord::parse(const char *buf, size_t len, const char *pos,
00702                                            size_t rrlen)
00703 {
00704         int ret;
00705 
00706         if (rrlen < 6)
00707         {
00708                 ret = ARES_EBADRESP;
00709                 goto bail;
00710         }
00711 
00712         memcpy(&mPriority, pos, 2);
00713         memcpy(&mWeight, pos + 2, 2);
00714         memcpy(&mPort, pos + 4, 2);
00715 
00716         mPriority = ntohs(mPriority);
00717         mWeight = ntohs(mWeight);
00718         mPort = ntohs(mPort);
00719 
00720         ret = LLHostRecord::parse(buf, len, pos + 6, rrlen - 6);
00721         
00722 bail:
00723         return ret;
00724 }
00725 
00726 LLNsRecord::LLNsRecord(const std::string &name, unsigned ttl)
00727         : LLHostRecord(RES_NS, name, ttl)
00728 {
00729 }
00730 
00731 void LLAres::UriRewriteResponder::queryError(int code)
00732 {
00733         std::vector<std::string> uris;
00734         uris.push_back(mUri.asString());
00735         rewriteResult(uris);
00736 }
00737 
00738 void LLAres::UriRewriteResponder::queryResult()
00739 {
00740         std::vector<std::string> uris;
00741 
00742         if (mType != RES_SRV)
00743         {
00744                 goto bail;
00745         }
00746                 
00747         for (size_t i = 0; i < mAnswers.size(); i++)
00748         {
00749                 const LLSrvRecord *r = (const LLSrvRecord *) mAnswers[i].get();
00750 
00751                 if (r->type() == RES_SRV)
00752                 {
00753                         // Check the domain in the response to ensure that it's
00754                         // the same as the domain in the request, so that bad guys
00755                         // can't forge responses that point to their own login
00756                         // servers with their own certificates.
00757 
00758                         // Hard-coding the domain to check here is a bit of a
00759                         // hack.  Hoist it to an outer caller if anyone ever needs
00760                         // this functionality on other domains.
00761 
00762                         static const std::string domain(".lindenlab.com");
00763                         const std::string &host = r->host();
00764 
00765                         std::string::size_type s = host.find(domain) + domain.length();
00766                                 
00767                         if (s != host.length() && s != host.length() - 1)
00768                         {
00769                                 continue;
00770                         }
00771                         
00772                         LLURI uri(mUri.scheme(),
00773                                           mUri.userName(),
00774                                           mUri.password(),
00775                                           r->host(),
00776                                           mUri.defaultPort() ? r->port() : mUri.hostPort(),
00777                                           mUri.escapedPath(),
00778                                           mUri.escapedQuery());
00779                         uris.push_back(uri.asString());
00780                 }
00781         }
00782 
00783         if (!uris.empty())
00784         {
00785                 goto done;
00786         }
00787 
00788 bail:
00789         uris.push_back(mUri.asString());
00790 
00791 done:
00792         rewriteResult(uris);
00793 }
00794 
00795 void LLAres::UriRewriteResponder::rewriteResult(
00796         const std::vector<std::string> &uris)
00797 {
00798         llinfos << "LLAres::UriRewriteResponder::rewriteResult not implemented"
00799                         << llendl;
00800 
00801         for (size_t i = 0; i < uris.size(); i++)
00802         {
00803                 llinfos << "[" << i << "] " << uris[i] << llendl;
00804         }
00805 }

Generated on Fri May 16 08:32:01 2008 for SecondLife by  doxygen 1.5.5