|
reSIProcate/rutil
9694
|
00001 #ifndef RESIP_DNS_STUB_HXX 00002 #define RESIP_DNS_STUB_HXX 00003 00004 #ifdef HAVE_CONFIG_H 00005 #include "config.h" 00006 #endif 00007 00008 00009 #include <vector> 00010 #include <list> 00011 #include <map> 00012 #include <set> 00013 00014 #include "rutil/FdPoll.hxx" 00015 #include "rutil/Fifo.hxx" 00016 #include "rutil/GenericIPAddress.hxx" 00017 #include "rutil/SelectInterruptor.hxx" 00018 #include "rutil/Socket.hxx" 00019 #include "rutil/dns/DnsResourceRecord.hxx" 00020 #include "rutil/dns/DnsAAAARecord.hxx" 00021 #include "rutil/dns/DnsCnameRecord.hxx" 00022 #include "rutil/dns/DnsHostRecord.hxx" 00023 #include "rutil/dns/DnsNaptrRecord.hxx" 00024 #include "rutil/dns/DnsSrvRecord.hxx" 00025 #include "rutil/dns/RRCache.hxx" 00026 #include "rutil/dns/RROverlay.hxx" 00027 #include "rutil/dns/ExternalDns.hxx" 00028 #include "rutil/AsyncProcessHandler.hxx" 00029 00030 00031 namespace resip 00032 { 00033 class FdPollGrp; 00034 00035 class GetDnsCacheDumpHandler 00036 { 00037 public: 00038 GetDnsCacheDumpHandler() {} 00039 virtual ~GetDnsCacheDumpHandler() {} 00040 virtual void onDnsCacheDumpRetrieved(std::pair<unsigned long, unsigned long> key, const Data& dnsCache) = 0; 00041 }; 00042 00043 template<typename T> 00044 class DNSResult 00045 { 00046 public: 00047 Data domain; 00048 int status; 00049 Data msg; 00050 std::vector<T> records; 00051 EncodeStream& dump(EncodeStream& strm) const 00052 { 00053 if (status == 0) 00054 { 00055 for (typename std::vector<T>::const_iterator i=records.begin(); i != records.end(); ++i) 00056 { 00057 i->dump(strm); 00058 } 00059 } 00060 else 00061 { 00062 strm << domain << " lookup failed: " << msg; 00063 } 00064 00065 return strm; 00066 } 00067 }; 00068 00069 template<class T> 00070 EncodeStream& operator<<(EncodeStream& strm, const DNSResult<T>& r) 00071 { 00072 r.dump(strm); 00073 return strm; 00074 } 00075 00076 class DnsResultSink 00077 { 00078 public: 00079 virtual ~DnsResultSink() {} 00080 virtual void onDnsResult(const DNSResult<DnsHostRecord>&) = 0; 00081 virtual void onLogDnsResult(const DNSResult<DnsHostRecord>&); 00082 00083 // DnsAAAARecord will basically be non-functional if USE_IPV6 wasn't set in the 00084 // build. 00085 virtual void onDnsResult(const DNSResult<DnsAAAARecord>&) = 0; 00086 virtual void onLogDnsResult(const DNSResult<DnsAAAARecord>&); 00087 00088 virtual void onDnsResult(const DNSResult<DnsSrvRecord>&) = 0; 00089 virtual void onLogDnsResult(const DNSResult<DnsSrvRecord>&); 00090 00091 virtual void onDnsResult(const DNSResult<DnsNaptrRecord>&) = 0; 00092 virtual void onLogDnsResult(const DNSResult<DnsNaptrRecord>&); 00093 00094 virtual void onDnsResult(const DNSResult<DnsCnameRecord>&) = 0; 00095 virtual void onLogDnsResult(const DNSResult<DnsCnameRecord>&); 00096 }; 00097 00098 class DnsRawSink 00099 { 00100 public: 00101 virtual ~DnsRawSink() {} 00102 virtual void onDnsRaw(int statuts, const unsigned char* abuf, int len) = 0; 00103 }; 00104 00105 class DnsStub : public ExternalDnsHandler 00106 { 00107 public: 00108 typedef RRCache::Protocol Protocol; 00109 typedef std::vector<Data> DataArr; 00110 typedef std::vector<DnsResourceRecord*> DnsResourceRecordsByPtr; 00111 typedef std::vector<GenericIPAddress> NameserverList; 00112 00113 static NameserverList EmptyNameserverList; 00114 00115 class ResultTransform 00116 { 00117 public: 00118 virtual ~ResultTransform() {} 00119 virtual void transform(const Data& target, int rrType, DnsResourceRecordsByPtr& src) = 0; 00120 }; 00121 00122 class DnsStubException : public BaseException 00123 { 00124 public: 00125 DnsStubException(const Data& msg, const Data& file, const int line) 00126 : BaseException(msg, file, line) 00127 { 00128 } 00129 00130 const char* name() const { return "DnsStubException"; } 00131 }; 00132 00133 DnsStub(const NameserverList& additional = EmptyNameserverList, 00134 AfterSocketCreationFuncPtr socketFunc = 0, 00135 AsyncProcessHandler* asyncProcessHandler = 0, 00136 FdPollGrp *pollGrp = 0); 00137 ~DnsStub(); 00138 00139 // call this method before you create SipStack if you'd like to change the 00140 // default DNS lookup timeout and number of retries. 00141 static void setDnsTimeoutAndTries(int timeoutInSec, int tries) 00142 { 00143 mDnsTimeout = timeoutInSec; 00144 mDnsTries = tries; 00145 } 00146 static void enableDnsFeatures(unsigned int features) {mDnsFeatures |= features;} // bit mask of ExternalDns::Features 00147 00148 void setResultTransform(ResultTransform*); 00149 void removeResultTransform(); 00150 void setEnumSuffixes(const std::vector<Data>& suffixes); 00151 const std::vector<Data>& getEnumSuffixes() const; 00152 void clearDnsCache(); 00153 void logDnsCache(); 00154 void getDnsCacheDump(std::pair<unsigned long, unsigned long> key, GetDnsCacheDumpHandler* handler); 00155 void setDnsCacheTTL(int ttl); 00156 void setDnsCacheSize(int size); 00157 bool checkDnsChange(); 00158 bool supportedType(int); 00159 00160 template<class QueryType> void lookup(const Data& target, DnsResultSink* sink) 00161 { 00162 lookup<QueryType>(target, Protocol::Reserved, sink); 00163 } 00164 00165 // There are three pre-defined protocols (see RRList.hxx). Zero(0) is 00166 // reserved for internal use, so do not use 0. If you'd like to blacklist 00167 // for different types of protocols, just pass in any integer other than 00168 // those used for pre-defined protocols. 00169 // 00170 template<class QueryType> void lookup(const Data& target, int protocol, DnsResultSink* sink) 00171 { 00172 QueryCommand<QueryType>* command = new QueryCommand<QueryType>(target, protocol, sink, *this); 00173 mCommandFifo.add(command); 00174 00175 if (mAsyncProcessHandler) 00176 { 00177 mAsyncProcessHandler->handleProcessNotification(); 00178 } 00179 } 00180 00181 virtual void handleDnsRaw(ExternalDnsRawResult); 00182 00183 virtual void process(FdSet& fdset); 00184 virtual unsigned int getTimeTillNextProcessMS(); 00185 virtual void buildFdSet(FdSet& fdset); 00186 void setPollGrp(FdPollGrp* pollGrp); 00187 00188 void processTimers(); 00189 private: 00190 void processFifo(); 00191 00192 protected: 00193 void cache(const Data& key, in_addr addr); 00194 void cache(const Data& key, const unsigned char* abuf, int alen); 00195 void cacheTTL(const Data& key, int rrType, int status, const unsigned char* abuf, int alen); 00196 00197 private: 00198 class ResultConverter //.dcm. -- flyweight? 00199 { 00200 public: 00201 virtual void notifyUser(const Data& target, 00202 int status, 00203 const Data& msg, 00204 const DnsResourceRecordsByPtr& src, 00205 DnsResultSink* sink) = 0; 00206 virtual ~ResultConverter() {} 00207 }; 00208 00209 template<class QueryType> 00210 class ResultConverterImpl : public ResultConverter 00211 { 00212 public: 00213 virtual void notifyUser(const Data& target, 00214 int status, 00215 const Data& msg, 00216 const DnsResourceRecordsByPtr& src, 00217 DnsResultSink* sink) 00218 { 00219 assert(sink); 00220 DNSResult<typename QueryType::Type> result; 00221 for (unsigned int i = 0; i < src.size(); ++i) 00222 { 00223 result.records.push_back(*(dynamic_cast<typename QueryType::Type*>(src[i]))); 00224 } 00225 result.domain = target; 00226 result.status = status; 00227 result.msg = msg; 00228 sink->onLogDnsResult(result); 00229 sink->onDnsResult(result); 00230 } 00231 }; 00232 00233 class Query : public DnsRawSink 00234 { 00235 public: 00236 Query(DnsStub& stub, ResultTransform* transform, ResultConverter* resultConv, 00237 const Data& target, int rrType, bool followCname, int proto, DnsResultSink* s); 00238 virtual ~Query(); 00239 00240 enum {MAX_REQUERIES = 5}; 00241 00242 void go(); 00243 void process(int status, const unsigned char* abuf, const int alen); 00244 void onDnsRaw(int status, const unsigned char* abuf, int alen); 00245 void followCname(const unsigned char* aptr, const unsigned char*abuf, const int alen, bool& bGotAnswers, bool& bDeleteThis, Data& targetToQuery); 00246 00247 private: 00248 static DnsResourceRecordsByPtr Empty; 00249 int mRRType; 00250 DnsStub& mStub; 00251 ResultTransform* mTransform; 00252 ResultConverter* mResultConverter; 00253 Data mTarget; 00254 int mProto; 00255 int mReQuery; 00256 DnsResultSink* mSink; 00257 bool mFollowCname; 00258 }; 00259 00260 private: 00261 DnsStub(const DnsStub&); // disable copy ctor. 00262 DnsStub& operator=(const DnsStub&); 00263 00264 public: 00265 // sailesh - due to a bug in CodeWarrior, 00266 // QueryCommand::execute() can only access this method 00267 // if it's public. Even using "friend" doesn't work. 00268 template<class QueryType> 00269 void query(const Data& target, int proto, DnsResultSink* sink) 00270 { 00271 Query* query = new Query(*this, mTransform, 00272 new ResultConverterImpl<QueryType>(), 00273 target, QueryType::getRRType(), 00274 QueryType::SupportsCName, proto, sink); 00275 mQueries.insert(query); 00276 query->go(); 00277 } 00278 00279 private: 00280 00281 class Command 00282 { 00283 public: 00284 virtual ~Command() {} 00285 virtual void execute() = 0; 00286 }; 00287 00288 00289 template<class QueryType> 00290 class QueryCommand : public Command 00291 { 00292 public: 00293 QueryCommand(const Data& target, 00294 int proto, 00295 DnsResultSink* sink, 00296 DnsStub& stub) 00297 : mTarget(target), 00298 mProto(proto), 00299 mSink(sink), 00300 mStub(stub) 00301 {} 00302 00303 ~QueryCommand() {} 00304 00305 void execute() 00306 { 00307 mStub.query<QueryType>(mTarget, mProto, mSink); 00308 } 00309 00310 private: 00311 Data mTarget; 00312 int mProto; 00313 DnsResultSink* mSink; 00314 DnsStub& mStub; 00315 }; 00316 00317 void doSetEnumSuffixes(const std::vector<Data>& suffixes); 00318 00319 class SetEnumSuffixesCommand : public Command 00320 { 00321 public: 00322 SetEnumSuffixesCommand(DnsStub& stub, 00323 const std::vector<Data>& suffixes) 00324 : mStub(stub), 00325 mEnumSuffixes(suffixes) 00326 {} 00327 ~SetEnumSuffixesCommand() {} 00328 void execute() 00329 { 00330 mStub.doSetEnumSuffixes(mEnumSuffixes); 00331 } 00332 00333 private: 00334 DnsStub& mStub; 00335 std::vector<Data> mEnumSuffixes; 00336 }; 00337 00338 void doClearDnsCache(); 00339 00340 class ClearDnsCacheCommand : public Command 00341 { 00342 public: 00343 ClearDnsCacheCommand(DnsStub& stub) 00344 : mStub(stub) 00345 {} 00346 ~ClearDnsCacheCommand() {} 00347 void execute() 00348 { 00349 mStub.doClearDnsCache(); 00350 } 00351 00352 private: 00353 DnsStub& mStub; 00354 }; 00355 00356 void doLogDnsCache(); 00357 00358 class LogDnsCacheCommand : public Command 00359 { 00360 public: 00361 LogDnsCacheCommand(DnsStub& stub) 00362 : mStub(stub) 00363 {} 00364 ~LogDnsCacheCommand() {} 00365 void execute() 00366 { 00367 mStub.doLogDnsCache(); 00368 } 00369 00370 private: 00371 DnsStub& mStub; 00372 }; 00373 00374 void doGetDnsCacheDump(std::pair<unsigned long, unsigned long> key, GetDnsCacheDumpHandler* handler); 00375 00376 class GetDnsCacheDumpCommand : public Command 00377 { 00378 public: 00379 GetDnsCacheDumpCommand(DnsStub& stub, std::pair<unsigned long, unsigned long> key, GetDnsCacheDumpHandler* handler) 00380 : mStub(stub), mKey(key), mHandler(handler) 00381 {} 00382 ~GetDnsCacheDumpCommand() {} 00383 void execute() 00384 { 00385 mStub.doGetDnsCacheDump(mKey, mHandler); 00386 } 00387 00388 private: 00389 DnsStub& mStub; 00390 std::pair<unsigned long, unsigned long> mKey; 00391 GetDnsCacheDumpHandler* mHandler; 00392 }; 00393 00394 SelectInterruptor mSelectInterruptor; 00395 FdPollItemHandle mInterruptorHandle; 00396 00397 resip::Fifo<Command> mCommandFifo; 00398 00399 const unsigned char* skipDNSQuestion(const unsigned char *aptr, 00400 const unsigned char *abuf, 00401 int alen); 00402 const unsigned char* createOverlay(const unsigned char* abuf, 00403 const int alen, 00404 const unsigned char* aptr, 00405 std::vector<RROverlay>&, 00406 bool discard=false); 00407 void removeQuery(Query*); 00408 void lookupRecords(const Data& target, unsigned short type, DnsRawSink* sink); 00409 Data errorMessage(int status); 00410 00411 ResultTransform* mTransform; 00412 ExternalDns* mDnsProvider; 00413 FdPollGrp* mPollGrp; 00414 std::set<Query*> mQueries; 00415 00416 std::vector<Data> mEnumSuffixes; // where to do enum lookups 00417 00418 static int mDnsTimeout; // in seconds 00419 static int mDnsTries; 00420 static unsigned int mDnsFeatures; // bit mask of ExternalDns::Features 00421 00423 AsyncProcessHandler* mAsyncProcessHandler; 00424 00426 RRCache mRRCache; 00427 }; 00428 00429 typedef DnsStub::Protocol Protocol; 00430 00431 } 00432 00433 #endif 00434 00435 /* ==================================================================== 00436 * The Vovida Software License, Version 1.0 00437 * 00438 * Copyright (c) 2000-2005 Vovida Networks, Inc. All rights reserved. 00439 * 00440 * Redistribution and use in source and binary forms, with or without 00441 * modification, are permitted provided that the following conditions 00442 * are met: 00443 * 00444 * 1. Redistributions of source code must retain the above copyright 00445 * notice, this list of conditions and the following disclaimer. 00446 * 00447 * 2. Redistributions in binary form must reproduce the above copyright 00448 * notice, this list of conditions and the following disclaimer in 00449 * the documentation and/or other materials provided with the 00450 * distribution. 00451 * 00452 * 3. The names "VOCAL", "Vovida Open Communication Application Library", 00453 * and "Vovida Open Communication Application Library (VOCAL)" must 00454 * not be used to endorse or promote products derived from this 00455 * software without prior written permission. For written 00456 * permission, please contact vocal@vovida.org. 00457 * 00458 * 4. Products derived from this software may not be called "VOCAL", nor 00459 * may "VOCAL" appear in their name, without prior written 00460 * permission of Vovida Networks, Inc. 00461 * 00462 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 00463 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00464 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND 00465 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA 00466 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES 00467 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, 00468 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00469 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00470 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 00471 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00472 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 00473 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 00474 * DAMAGE. 00475 * 00476 * ==================================================================== 00477 * 00478 * This software consists of voluntary contributions made by Vovida 00479 * Networks, Inc. and many individuals on behalf of Vovida Networks, 00480 * Inc. For more information on Vovida Networks, Inc., please see 00481 * <http://www.vovida.org/>. 00482 * 00483 */ 00484
1.7.5.1