00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 #if P_DNS
00032 #ifndef _PDNS_H
00033 #define _PDNS_H
00034 
00035 #ifdef P_USE_PRAGMA
00036 #pragma interface
00037 #endif
00038 
00039 #include <ptlib/sockets.h>
00040 
00041 #include <ptclib/random.h>
00042 #include <ptclib/url.h>
00043 
00044 #if defined(_WIN32)
00045 
00046 #  include <windns.h>
00047 #  pragma comment(lib, P_DNS_LIBRARY)
00048 
00049 
00050 #ifndef __MINGW32__
00051 enum { DnsSectionAdditional = DnsSectionAddtional };
00052 #endif
00053 
00054 #else 
00055 
00056 #  define  P_HAS_RESOLVER 1         // set if using Unix-style DNS routines
00057 #  include <arpa/nameser.h>
00058 #  include <resolv.h>
00059 #  if defined(P_MACOSX) && (P_MACOSX >= 700)
00060 #    include <arpa/nameser_compat.h>
00061 #  endif
00062 
00063 #endif  // _WIN32
00064 
00065 #ifdef P_HAS_RESOLVER
00066 
00068 
00069 
00070 
00071 
00072 
00073 #ifndef T_SRV
00074 #define T_SRV   33
00075 #endif
00076 
00077 #ifndef T_NAPTR
00078 #define T_NAPTR   35
00079 #endif
00080 
00081 
00082 #define DNS_STATUS  int
00083 #define DNS_TYPE_SRV  T_SRV
00084 #define DNS_TYPE_MX  T_MX
00085 #define DNS_TYPE_A  T_A
00086 #define DNS_TYPE_NAPTR  T_NAPTR
00087 #define DnsFreeRecordList 0
00088 #define DNS_QUERY_STANDARD 0
00089 #define DNS_QUERY_BYPASS_CACHE 0
00090 
00091 typedef struct _DnsAData {
00092   DWORD IpAddress;
00093 } DNS_A_DATA;
00094 
00095 typedef struct {
00096   char   pNameExchange[MAXDNAME];
00097   WORD   wPreference;
00098 } DNS_MX_DATA;
00099 
00100 typedef struct {
00101   char pNameHost[MAXDNAME];
00102 } DNS_PTR_DATA;
00103 
00104 typedef struct _DnsSRVData {
00105   char   pNameTarget[MAXDNAME];
00106   WORD   wPriority;
00107   WORD   wWeight;
00108   WORD   wPort;
00109 } DNS_SRV_DATA;
00110 
00111 typedef struct _DnsNULLData {
00112   DWORD  dwByteCount;
00113   char   data[1];
00114 } DNS_NULL_DATA;
00115 
00116 typedef struct _DnsRecordFlags
00117 {
00118   unsigned   Section     : 2;
00119   unsigned   Delete      : 1;
00120   unsigned   CharSet     : 2;
00121   unsigned   Unused      : 3;
00122   unsigned   Reserved    : 24;
00123 } DNS_RECORD_FLAGS;
00124 
00125 typedef enum _DnsSection
00126 {
00127   DnsSectionQuestion,
00128   DnsSectionAnswer,
00129   DnsSectionAuthority,
00130   DnsSectionAdditional,
00131 } DNS_SECTION;
00132 
00133 
00134 class DnsRecord {
00135   public:
00136     DnsRecord * pNext;
00137     char        pName[MAXDNAME];
00138     WORD        wType;
00139     WORD        wDataLength;
00140 
00141     union {
00142       DWORD               DW;     
00143       DNS_RECORD_FLAGS    S;      
00144     } Flags;
00145 
00146     union {
00147       DNS_A_DATA     A;
00148       DNS_MX_DATA    MX;
00149       DNS_PTR_DATA   NS;
00150       DNS_SRV_DATA   SRV;
00151       DNS_NULL_DATA  Null;
00152     } Data;
00153 };
00154 
00155 typedef DnsRecord * PDNS_RECORD;
00156 
00157 extern void DnsRecordListFree(PDNS_RECORD rec, int FreeType);
00158 
00159 extern DNS_STATUS DnsQuery_A(const char * service,
00160           WORD requestType,
00161           DWORD options,
00162           void *,
00163           PDNS_RECORD * results,
00164           void *);
00165 
00166 
00167 #endif // P_HAS_RESOLVER
00168 
00169 namespace PDNS {
00170 
00172 
00173 
00174 
00175 
00176 
00177 template <unsigned type, class RecordListType, class RecordType>
00178 PBoolean Lookup(const PString & name, RecordListType & recordList)
00179 {
00180   if (name.IsEmpty())
00181     return PFalse;
00182 
00183   recordList.RemoveAll();
00184 
00185   PDNS_RECORD results = NULL;
00186   DNS_STATUS status = DnsQuery_A((const char *)name, 
00187                                  type,
00188                                  DNS_QUERY_STANDARD, 
00189                                  NULL, 
00190                                  &results, 
00191                                  NULL);
00192   if (status != 0)
00193     return PFalse;
00194 
00195   
00196   PDNS_RECORD dnsRecord = results;
00197   while (dnsRecord != NULL) {
00198     RecordType * record = recordList.HandleDNSRecord(dnsRecord, results);
00199     if (record != NULL)
00200       recordList.Append(record);
00201     dnsRecord = dnsRecord->pNext;
00202   }
00203 
00204   if (results != NULL)
00205     DnsRecordListFree(results, DnsFreeRecordList);
00206 
00207   return recordList.GetSize() != 0;
00208 }
00209 
00211 
00212 class SRVRecord : public PObject
00213 {
00214   PCLASSINFO(SRVRecord, PObject);
00215   public:
00216     SRVRecord()
00217     { used = PFalse; }
00218 
00219     Comparison Compare(const PObject & obj) const;
00220     void PrintOn(ostream & strm) const;
00221 
00222     PString            hostName;
00223     PIPSocket::Address hostAddress;
00224     PBoolean               used;
00225     WORD port;
00226     WORD priority;
00227     WORD weight;
00228 };
00229 
00230 PDECLARE_SORTED_LIST(SRVRecordList, PDNS::SRVRecord)
00231   public:
00232     void PrintOn(ostream & strm) const;
00233 
00234     SRVRecord * GetFirst();
00235     SRVRecord * GetNext();
00236 
00237     PDNS::SRVRecord * HandleDNSRecord(PDNS_RECORD dnsRecord, PDNS_RECORD results);
00238 
00239   protected:
00240     PINDEX     priPos;
00241     PWORDArray priList;
00242 };
00243 
00248 inline PBoolean GetRecords(const PString & service, SRVRecordList & serviceList)
00249 { return Lookup<DNS_TYPE_SRV, SRVRecordList, SRVRecord>(service, serviceList); }
00250 
00254 inline PBoolean GetSRVRecords(
00255       const PString & service,
00256       SRVRecordList & serviceList
00257 )
00258 { return GetRecords(service, serviceList); }
00259 
00264 PBoolean GetSRVRecords(
00265       const PString & service,
00266       const PString & type,
00267       const PString & domain,
00268       SRVRecordList & serviceList
00269 );
00270 
00276 PBoolean LookupSRV(
00277          const PString & srvQuery,
00278          WORD defaultPort,
00279          PIPSocketAddressAndPortVector & addrList
00280 );
00281 
00282 PBoolean LookupSRV( 
00283          const PString & domain,                  
00284          const PString & service,                 
00285          WORD defaultPort,                        
00286          PIPSocketAddressAndPortVector & addrList 
00287 ); 
00288 
00289 PBoolean LookupSRV( 
00290          const PURL & url,          
00291          const PString & service,   
00292          PStringList & returnStr    
00293 );  
00294 
00296 
00297 class MXRecord : public PObject
00298 {
00299   PCLASSINFO(MXRecord, PObject);
00300   public:
00301     MXRecord()
00302     { used = PFalse; }
00303     Comparison Compare(const PObject & obj) const;
00304     void PrintOn(ostream & strm) const;
00305 
00306     PString            hostName;
00307     PIPSocket::Address hostAddress;
00308     PBoolean               used;
00309     WORD               preference;
00310 };
00311 
00312 PDECLARE_SORTED_LIST(MXRecordList, PDNS::MXRecord)
00313   public:
00314     void PrintOn(ostream & strm) const;
00315 
00316     MXRecord * GetFirst();
00317     MXRecord * GetNext();
00318 
00319     PDNS::MXRecord * HandleDNSRecord(PDNS_RECORD dnsRecord, PDNS_RECORD results);
00320 
00321   protected:
00322     PINDEX lastIndex;
00323 };
00324 
00328 inline PBoolean GetRecords(
00329       const PString & domain,
00330       MXRecordList & serviceList
00331 )
00332 { return Lookup<DNS_TYPE_MX, MXRecordList, MXRecord>(domain, serviceList); }
00333 
00337 inline PBoolean GetMXRecords(
00338       const PString & domain,
00339       MXRecordList & serviceList
00340 )
00341 {
00342   return GetRecords(domain, serviceList);
00343 }
00344 
00346 
00347 }; 
00348 
00349 #endif // _PDNS_H
00350 #endif // P_DNS
00351 
00352