1 /*
2 * pdns.h
3 *
4 * PWLib library for DNS lookup services
5 *
6 * Portable Windows Library
7 *
8 * Copyright (c) 2003 Equivalence Pty. Ltd.
9 *
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
14 *
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * The Original Code is Portable Windows Library.
21 *
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
23 *
24 * Contributor(s): ______________________________________.
25 *
26 * $Revision: 28568 $
27 * $Author: rjongbloed $
28 * $Date: 2012-11-22 00:16:50 -0600 (Thu, 22 Nov 2012) $
29 */
30
31 #ifndef PTLIB_PDNS_H
32 #define PTLIB_PDNS_H
33
34 #if P_DNS
35
36 #ifdef P_USE_PRAGMA
37 #pragma interface
38 #endif
39
40 #include <ptlib/sockets.h>
41
42 #include <ptclib/random.h>
43 #include <ptclib/url.h>
44
45 #if defined(_WIN32)
46
47 #include <windns.h>
48 #include <ntverp.h>
49
50 // Accommodate spelling error in windns.h
51 enum { DnsSectionAdditional = DnsSectionAddtional };
52
53 #if VER_PRODUCTBUILD < 6000
54 typedef struct
55 {
56 WORD wOrder;
57 WORD wPreference;
58 PSTR pFlags;
59 PSTR pService;
60 PSTR pRegularExpression;
61 PSTR pReplacement;
62 }
63 DNS_NAPTR_DATA;
64 #endif
65
66 #else /* _WIN32 */
67
68 #define P_HAS_RESOLVER 1 // set if using Unix-style DNS routines
69 #include <arpa/nameser.h>
70 #include <resolv.h>
71 #if defined(P_MACOSX) && (P_MACOSX >= 700)
72 #include <arpa/nameser_compat.h>
73 #endif
74
75 #endif // _WIN32
76
77
78 #ifdef P_HAS_RESOLVER
79
80 //////////////////////////////////////////////////////////////////////////
81 //
82 // these classes provide an emulation of the Microsoft DNS API
83 // on non-Window systems
84 //
85
86 #ifndef T_SRV
87 #define T_SRV 33
88 #endif
89
90 #ifndef T_NAPTR
91 #define T_NAPTR 35
92 #endif
93
94
95 #define DNS_STATUS int
96 #define DNS_TYPE_SRV T_SRV
97 #define DNS_TYPE_MX T_MX
98 #define DNS_TYPE_A T_A
99 #define DNS_TYPE_AAAA T_AAAA
100 #define DNS_TYPE_NAPTR T_NAPTR
101 #define DnsFreeRecordList 1
102 #define DNS_QUERY_STANDARD 0
103 #define DNS_QUERY_BYPASS_CACHE 0
104
105 typedef struct _DnsAData {
106 DWORD IpAddress;
107 } DNS_A_DATA;
108
109 typedef struct _DnsAAAAData {
110 DWORD Ip6Address[4];
111 } DNS_AAAA_DATA;
112
113 typedef struct {
114 char pNameExchange[MAXDNAME];
115 WORD wPreference;
116 } DNS_MX_DATA;
117
118 typedef struct {
119 char pNameHost[MAXDNAME];
120 } DNS_PTR_DATA;
121
122 typedef struct _DnsSRVData {
123 char pNameTarget[MAXDNAME];
124 WORD wPriority;
125 WORD wWeight;
126 WORD wPort;
127 } DNS_SRV_DATA;
128
129 typedef struct _DnsNULLData {
130 DWORD dwByteCount;
131 char data[1];
132 } DNS_NULL_DATA;
133
134 typedef struct _DnsRecordFlags
135 {
136 unsigned Section : 2;
137 unsigned Delete : 1;
138 unsigned CharSet : 2;
139 unsigned Unused : 3;
140 unsigned Reserved : 24;
141 } DNS_RECORD_FLAGS;
142
143 typedef enum _DnsSection
144 {
145 DnsSectionQuestion,
146 DnsSectionAnswer,
147 DnsSectionAuthority,
148 DnsSectionAdditional,
149 } DNS_SECTION;
150
151
152 class DnsRecord {
153 public:
154 DnsRecord * pNext;
155 char pName[MAXDNAME];
156 WORD wType;
157 WORD wDataLength;
158
159 union {
160 DWORD DW; ///< flags as DWORD
161 DNS_RECORD_FLAGS S; ///< flags as structure
162 } Flags;
163
164 union {
165 DNS_A_DATA A;
166 DNS_AAAA_DATA AAAA;
167 DNS_MX_DATA MX;
168 DNS_PTR_DATA NS;
169 DNS_SRV_DATA SRV;
170 DNS_NULL_DATA Null;
171 } Data;
172 };
173
174 typedef DnsRecord DNS_RECORD;
175 typedef DnsRecord * PDNS_RECORD;
176
177
178 extern void DnsRecordListFree(PDNS_RECORD rec, int FreeType);
179 extern PDNS_RECORD DnsRecordSetCopy(PDNS_RECORD src);
180
181 extern DNS_STATUS DnsQuery_A(const char * service,
182 WORD requestType,
183 DWORD options,
184 void *,
185 PDNS_RECORD * results,
186 void *);
187
188
189 #endif // P_HAS_RESOLVER
190
191 namespace PDNS {
192
193 ///////////////////////////////////////////////////////////////////////////
194
195 DNS_STATUS Cached_DnsQuery(
196 const char * name,
197 WORD type,
198 DWORD options,
199 void * extra,
200 PDNS_RECORD * queryResults,
201 void * reserved
202 );
203
204
205
206 //////////////////////////////////////////////////////////////////////////
207 //
208 // this template automates the creation of a list of records for
209 // a specific type of DNS lookup
210 //
211
212 template <unsigned type, class RecordListType, class RecordType>
Lookup(const PString & name,RecordListType & recordList)213 PBoolean Lookup(const PString & name, RecordListType & recordList)
214 {
215 if (name.IsEmpty())
216 return false;
217
218 recordList.RemoveAll();
219
220 PDNS_RECORD results = NULL;
221 DNS_STATUS status = Cached_DnsQuery((const char *)name,
222 type,
223 DNS_QUERY_STANDARD,
224 NULL,
225 &results,
226 NULL);
227 if (status != 0)
228 return false;
229
230 // find records matching the correct type
231 PDNS_RECORD dnsRecord = results;
232 while (dnsRecord != NULL) {
233 RecordType * record = recordList.HandleDNSRecord(dnsRecord, results);
234 if (record != NULL)
235 recordList.Append(record);
236 dnsRecord = dnsRecord->pNext;
237 }
238
239 if (results != NULL)
240 DnsRecordListFree(results, DnsFreeRecordList);
241
242 return recordList.GetSize() != 0;
243 }
244
245 /////////////////////////////////////////////////////////////
246
247 class SRVRecord : public PObject
248 {
249 PCLASSINFO(SRVRecord, PObject);
250 public:
SRVRecord()251 SRVRecord()
252 { used = false; }
253
254 Comparison Compare(const PObject & obj) const;
255 void PrintOn(ostream & strm) const;
256
257 PString hostName;
258 PIPSocket::Address hostAddress;
259 PBoolean used;
260 WORD port;
261 WORD priority;
262 WORD weight;
263 };
264
265 PDECLARE_SORTED_LIST(SRVRecordList, PDNS::SRVRecord)
266 public:
267 void PrintOn(ostream & strm) const;
268
269 SRVRecord * GetFirst();
270 SRVRecord * GetNext();
271
272 PDNS::SRVRecord * HandleDNSRecord(PDNS_RECORD dnsRecord, PDNS_RECORD results);
273
274 protected:
275 PINDEX priPos;
276 PWORDArray priList;
277 };
278
279 /**
280 * return a list of DNS SRV record with the specified service type
281 */
282
GetRecords(const PString & service,SRVRecordList & serviceList)283 inline PBoolean GetRecords(const PString & service, SRVRecordList & serviceList)
284 { return Lookup<DNS_TYPE_SRV, SRVRecordList, SRVRecord>(service, serviceList); }
285
286 /**
287 * provided for backwards compatibility
288 */
GetSRVRecords(const PString & service,SRVRecordList & serviceList)289 inline PBoolean GetSRVRecords(
290 const PString & service,
291 SRVRecordList & serviceList
292 )
293 { return GetRecords(service, serviceList); }
294
295 /**
296 * return a list of DNS SRV record with the specified service, type and domain
297 */
298
299 PBoolean GetSRVRecords(
300 const PString & service,
301 const PString & type,
302 const PString & domain,
303 SRVRecordList & serviceList
304 );
305
306 /**
307 * Perform a DNS lookup of the specified service
308 * @return true if the service could be resolved, else false
309 */
310
311 PBoolean LookupSRV(
312 const PString & srvQuery,
313 WORD defaultPort,
314 PIPSocketAddressAndPortVector & addrList
315 );
316
317 PBoolean LookupSRV(
318 const PString & domain, ///< domain to lookup
319 const PString & service, ///< service to use
320 WORD defaultPort, ///< default por to use
321 PIPSocketAddressAndPortVector & addrList ///< returned list of sockets and ports
322 );
323
324 PBoolean LookupSRV(
325 const PURL & url, ///< URL to lookup
326 const PString & service, ///< service to use
327 PStringList & returnStr ///< resolved addresses, if return value is true
328 );
329
330 ////////////////////////////////////////////////////////////////
331
332 class MXRecord : public PObject
333 {
334 PCLASSINFO(MXRecord, PObject);
335 public:
MXRecord()336 MXRecord()
337 { used = false; }
338 Comparison Compare(const PObject & obj) const;
339 void PrintOn(ostream & strm) const;
340
341 PString hostName;
342 PIPSocket::Address hostAddress;
343 PBoolean used;
344 WORD preference;
345 };
346
347 PDECLARE_SORTED_LIST(MXRecordList, PDNS::MXRecord)
348 public:
349 void PrintOn(ostream & strm) const;
350
351 MXRecord * GetFirst();
352 MXRecord * GetNext();
353
354 PDNS::MXRecord * HandleDNSRecord(PDNS_RECORD dnsRecord, PDNS_RECORD results);
355
356 protected:
357 PINDEX lastIndex;
358 };
359
360 /**
361 * return a list of MX records for the specified domain
362 */
363 inline PBoolean GetRecords(
364 const PString & domain,
365 MXRecordList & serviceList
366 )
367 { return Lookup<DNS_TYPE_MX, MXRecordList, MXRecord>(domain, serviceList); }
368
369 /**
370 * provided for backwards compatibility
371 */
372 inline PBoolean GetMXRecords(
373 const PString & domain,
374 MXRecordList & serviceList
375 )
376 {
377 return GetRecords(domain, serviceList);
378 }
379
380
381 }; // namespace PDNS
382
383 #endif // P_DNS
384
385 #endif // PTLIB_PDNS_H
386
387
388 // End Of File ///////////////////////////////////////////////////////////////
389