0
# DNS Queries
1
2
Comprehensive DNS query operations supporting all major record types including A, AAAA, MX, TXT, SOA, SRV, and others. All queries are asynchronous and use callback-based completion notification.
3
4
## Capabilities
5
6
### Query Operations
7
8
Perform DNS queries for specific record types. Supports both direct queries and search-based queries that use configured search domains.
9
10
```python { .api }
11
def query(self, name: str, query_type: int, callback, query_class: Optional[int] = None) -> None:
12
"""
13
Perform a DNS query for a specific record type.
14
15
Args:
16
name: str - Domain name to query
17
query_type: int - DNS record type (QUERY_TYPE_* constants)
18
callback: Callable - Function called with (result, error) when complete
19
query_class: Optional[int] - DNS class (default: QUERY_CLASS_IN)
20
21
Raises:
22
TypeError: If callback is not callable
23
ValueError: If query_type or query_class is invalid
24
RuntimeError: If channel is destroyed
25
"""
26
27
def search(self, name: str, query_type: int, callback, query_class: Optional[int] = None) -> None:
28
"""
29
Perform a DNS search query using configured search domains.
30
31
Similar to query() but will try appending search domains if the initial
32
query fails and the name doesn't contain enough dots (controlled by ndots).
33
34
Args:
35
name: str - Domain name to search for
36
query_type: int - DNS record type (QUERY_TYPE_* constants)
37
callback: Callable - Function called with (result, error) when complete
38
query_class: Optional[int] - DNS class (default: QUERY_CLASS_IN)
39
40
Raises:
41
TypeError: If callback is not callable
42
ValueError: If query_type or query_class is invalid
43
RuntimeError: If channel is destroyed
44
"""
45
```
46
47
**Usage Example:**
48
49
```python
50
import pycares
51
52
def query_callback(result, error):
53
if error is not None:
54
print(f'DNS Error: {pycares.errno.strerror(error)}')
55
return
56
57
if isinstance(result, list):
58
for record in result:
59
print(f'{record.type} record: {record}')
60
else:
61
print(f'{result.type} record: {result}')
62
63
channel = pycares.Channel()
64
65
# Direct query for A records
66
channel.query('google.com', pycares.QUERY_TYPE_A, query_callback)
67
68
# Search query with domain search
69
channel.search('mail', pycares.QUERY_TYPE_MX, query_callback)
70
71
# Query for TXT records
72
channel.query('google.com', pycares.QUERY_TYPE_TXT, query_callback)
73
```
74
75
## Query Types
76
77
DNS record types supported for queries:
78
79
```python { .api }
80
# IPv4 address records
81
QUERY_TYPE_A = 1
82
83
# IPv6 address records
84
QUERY_TYPE_AAAA = 28
85
86
# Canonical name records
87
QUERY_TYPE_CNAME = 5
88
89
# Mail exchange records
90
QUERY_TYPE_MX = 15
91
92
# Text records
93
QUERY_TYPE_TXT = 16
94
95
# Name server records
96
QUERY_TYPE_NS = 2
97
98
# Pointer records (reverse DNS)
99
QUERY_TYPE_PTR = 12
100
101
# Start of authority records
102
QUERY_TYPE_SOA = 6
103
104
# Service location records
105
QUERY_TYPE_SRV = 33
106
107
# Certification Authority Authorization records
108
QUERY_TYPE_CAA = 257
109
110
# Naming Authority Pointer records
111
QUERY_TYPE_NAPTR = 35
112
113
# Query for any available record type
114
QUERY_TYPE_ANY = 255
115
```
116
117
## Query Classes
118
119
DNS query classes (rarely needed, defaults to IN):
120
121
```python { .api }
122
# Internet class (default)
123
QUERY_CLASS_IN = 1
124
125
# CHAOS class
126
QUERY_CLASS_CHAOS = 3
127
128
# Hesiod class
129
QUERY_CLASS_HS = 4
130
131
# None class
132
QUERY_CLASS_NONE = 254
133
134
# Any class
135
QUERY_CLASS_ANY = 255
136
```
137
138
## Result Types
139
140
Each DNS record type returns specific result objects with relevant attributes:
141
142
### A Record Results
143
144
```python { .api }
145
class ares_query_a_result:
146
"""IPv4 address record result."""
147
type = 'A'
148
host: str # IPv4 address as string
149
ttl: int # Time to live in seconds
150
```
151
152
### AAAA Record Results
153
154
```python { .api }
155
class ares_query_aaaa_result:
156
"""IPv6 address record result."""
157
type = 'AAAA'
158
host: str # IPv6 address as string
159
ttl: int # Time to live in seconds
160
```
161
162
### CNAME Record Results
163
164
```python { .api }
165
class ares_query_cname_result:
166
"""Canonical name record result."""
167
type = 'CNAME'
168
cname: str # Canonical name
169
ttl: int # Time to live (-1 if not available)
170
```
171
172
### MX Record Results
173
174
```python { .api }
175
class ares_query_mx_result:
176
"""Mail exchange record result."""
177
type = 'MX'
178
host: str # Mail server hostname
179
priority: int # Mail server priority (lower = higher priority)
180
ttl: int # Time to live (-1 if not available)
181
```
182
183
### TXT Record Results
184
185
```python { .api }
186
class ares_query_txt_result:
187
"""Text record result."""
188
type = 'TXT'
189
text: str # Text content
190
ttl: int # Time to live (-1 if not available)
191
```
192
193
### NS Record Results
194
195
```python { .api }
196
class ares_query_ns_result:
197
"""Name server record result."""
198
type = 'NS'
199
host: str # Name server hostname
200
ttl: int # Time to live (-1 if not available)
201
```
202
203
### PTR Record Results
204
205
```python { .api }
206
class ares_query_ptr_result:
207
"""Pointer record result."""
208
type = 'PTR'
209
name: str # Domain name
210
ttl: int # Time to live (-1 if not available)
211
aliases: list[str] # List of aliases
212
```
213
214
### SOA Record Results
215
216
```python { .api }
217
class ares_query_soa_result:
218
"""Start of authority record result."""
219
type = 'SOA'
220
nsname: str # Primary name server
221
hostmaster: str # Responsible person's email
222
serial: int # Serial number
223
refresh: int # Refresh interval in seconds
224
retry: int # Retry interval in seconds
225
expires: int # Expiration time in seconds
226
minttl: int # Minimum TTL in seconds
227
ttl: int # Time to live (-1 if not available)
228
```
229
230
### SRV Record Results
231
232
```python { .api }
233
class ares_query_srv_result:
234
"""Service record result."""
235
type = 'SRV'
236
host: str # Target hostname
237
port: int # Service port number
238
priority: int # Priority (lower = higher priority)
239
weight: int # Weight for load balancing
240
ttl: int # Time to live (-1 if not available)
241
```
242
243
### CAA Record Results
244
245
```python { .api }
246
class ares_query_caa_result:
247
"""Certification Authority Authorization record result."""
248
type = 'CAA'
249
critical: int # Critical flag (0 or 1)
250
property: str # Property name (e.g., 'issue', 'issuewild', 'iodef')
251
value: str # Property value
252
ttl: int # Time to live (-1 if not available)
253
```
254
255
### NAPTR Record Results
256
257
```python { .api }
258
class ares_query_naptr_result:
259
"""Naming Authority Pointer record result."""
260
type = 'NAPTR'
261
order: int # Order preference
262
preference: int # Preference within same order
263
flags: str # Flags string
264
service: str # Service parameters
265
regex: str # Regular expression
266
replacement: str # Replacement string
267
ttl: int # Time to live (-1 if not available)
268
```
269
270
## Usage Examples
271
272
### A Record Lookup
273
274
```python
275
def a_record_callback(result, error):
276
if error:
277
print(f'Error: {pycares.errno.strerror(error)}')
278
return
279
280
for record in result:
281
print(f'A record: {record.host} (TTL: {record.ttl})')
282
283
channel.query('google.com', pycares.QUERY_TYPE_A, a_record_callback)
284
```
285
286
### MX Record Lookup
287
288
```python
289
def mx_record_callback(result, error):
290
if error:
291
print(f'Error: {pycares.errno.strerror(error)}')
292
return
293
294
# Sort by priority (lower number = higher priority)
295
mx_records = sorted(result, key=lambda x: x.priority)
296
297
for record in mx_records:
298
print(f'MX record: {record.host} (priority: {record.priority})')
299
300
channel.query('google.com', pycares.QUERY_TYPE_MX, mx_record_callback)
301
```
302
303
### TXT Record Lookup
304
305
```python
306
def txt_record_callback(result, error):
307
if error:
308
print(f'Error: {pycares.errno.strerror(error)}')
309
return
310
311
for record in result:
312
print(f'TXT record: {record.text}')
313
314
channel.query('google.com', pycares.QUERY_TYPE_TXT, txt_record_callback)
315
```
316
317
### ANY Query (Multiple Record Types)
318
319
```python
320
def any_query_callback(result, error):
321
if error:
322
print(f'Error: {pycares.errno.strerror(error)}')
323
return
324
325
for record in result:
326
if record.type == 'A':
327
print(f'A: {record.host}')
328
elif record.type == 'AAAA':
329
print(f'AAAA: {record.host}')
330
elif record.type == 'MX':
331
print(f'MX: {record.host} (priority: {record.priority})')
332
elif record.type == 'TXT':
333
print(f'TXT: {record.text}')
334
else:
335
print(f'{record.type}: {record}')
336
337
channel.query('google.com', pycares.QUERY_TYPE_ANY, any_query_callback)
338
```
339
340
### Reverse DNS Lookup (PTR)
341
342
```python
343
def ptr_callback(result, error):
344
if error:
345
print(f'Error: {pycares.errno.strerror(error)}')
346
return
347
348
for record in result:
349
print(f'PTR: {record.name}')
350
if record.aliases:
351
print(f'Aliases: {", ".join(record.aliases)}')
352
353
# Reverse lookup for IP address
354
channel.query('8.8.8.8.in-addr.arpa', pycares.QUERY_TYPE_PTR, ptr_callback)
355
```
356
357
## Error Handling
358
359
All query callbacks receive an error parameter. Common DNS errors include:
360
361
- **ARES_ENOTFOUND**: Domain name not found
362
- **ARES_ETIMEOUT**: Query timed out
363
- **ARES_ESERVFAIL**: DNS server failure
364
- **ARES_ENODATA**: No data in response
365
- **ARES_ECANCELLED**: Query was cancelled
366
367
See [Error Handling](./error-handling.md) for complete error code documentation.