0
# DNS Channel Management
1
2
Core functionality for creating, configuring, and managing DNS resolution channels. The Channel class serves as the primary interface for all DNS operations in pycares.
3
4
## Capabilities
5
6
### Channel Creation
7
8
Create a new DNS resolution channel with comprehensive configuration options for controlling query behavior, server selection, and network settings.
9
10
```python { .api }
11
class Channel:
12
def __init__(
13
self,
14
flags=None, # Optional[int]: Channel behavior flags
15
timeout=None, # Optional[float]: Query timeout in seconds
16
tries=None, # Optional[int]: Number of query attempts
17
ndots=None, # Optional[int]: Number of dots for domain search
18
tcp_port=None, # Optional[int]: TCP port for DNS queries
19
udp_port=None, # Optional[int]: UDP port for DNS queries
20
servers=None, # Optional[Iterable[Union[str, bytes]]]: DNS servers list
21
domains=None, # Optional[Iterable[Union[str, bytes]]]: Search domains
22
lookups=None, # Union[str, bytes, None]: Lookup order
23
sock_state_cb=None, # Optional[Callable[[int, bool, bool], None]]: Socket state callback
24
socket_send_buffer_size=None, # Optional[int]: Send buffer size
25
socket_receive_buffer_size=None, # Optional[int]: Receive buffer size
26
rotate=False, # bool: Rotate server list
27
local_ip=None, # Union[str, bytes, None]: Local IP binding
28
local_dev=None, # Optional[str]: Local device binding
29
resolvconf_path=None, # Union[str, bytes, None]: Custom resolv.conf path
30
event_thread=False # bool: Use event thread mode
31
):
32
"""
33
Create a new DNS resolution channel.
34
35
Args:
36
flags: Bitwise OR of ARES_FLAG_* constants for channel behavior
37
timeout: Query timeout in seconds (default uses system settings)
38
tries: Number of times to try each query (default: 4)
39
ndots: Number of dots needed in name for initial absolute query
40
tcp_port: TCP port number for DNS queries (default: 53)
41
udp_port: UDP port number for DNS queries (default: 53)
42
servers: List of DNS server IP addresses as strings
43
domains: List of search domains for unqualified names
44
lookups: String specifying lookup order (e.g., "bf" for bind then file)
45
sock_state_cb: Callback for socket state changes (fd, readable, writable)
46
socket_send_buffer_size: SO_SNDBUF socket option value
47
socket_receive_buffer_size: SO_RCVBUF socket option value
48
rotate: Whether to rotate through servers for load balancing
49
local_ip: Local IP address to bind outgoing queries to
50
local_dev: Local network device to bind to
51
resolvconf_path: Path to custom resolv.conf file
52
event_thread: Enable built-in event thread (requires thread-safe c-ares)
53
54
Raises:
55
AresError: If channel initialization fails
56
RuntimeError: If event_thread=True but c-ares not thread-safe
57
"""
58
```
59
60
**Usage Example:**
61
62
```python
63
import pycares
64
65
# Basic channel with custom servers
66
channel = pycares.Channel(
67
servers=['8.8.8.8', '8.8.4.4'],
68
timeout=5.0,
69
tries=2
70
)
71
72
# Advanced channel configuration
73
channel = pycares.Channel(
74
flags=pycares.ARES_FLAG_USEVC | pycares.ARES_FLAG_IGNTC,
75
servers=['1.1.1.1', '1.0.0.1'],
76
domains=['example.com', 'test.org'],
77
timeout=3.0,
78
tries=3,
79
rotate=True
80
)
81
```
82
83
### I/O Event Management
84
85
Functions for integrating DNS channel I/O with external event loops and monitoring systems. These functions enable non-blocking operation by allowing the application to monitor and process socket events.
86
87
```python { .api }
88
def getsock(self):
89
"""
90
Get socket file descriptors for I/O monitoring.
91
92
Returns:
93
tuple[list[int], list[int]]: (read_fds, write_fds) - Lists of socket
94
file descriptors ready for reading and writing
95
"""
96
97
def process_fd(self, read_fd: int, write_fd: int) -> None:
98
"""
99
Process I/O events on specific file descriptors.
100
101
Args:
102
read_fd: File descriptor ready for reading (or ARES_SOCKET_BAD if none)
103
write_fd: File descriptor ready for writing (or ARES_SOCKET_BAD if none)
104
"""
105
106
def process_read_fd(self, read_fd: int) -> None:
107
"""
108
Process read events on a file descriptor.
109
110
Args:
111
read_fd: File descriptor ready for reading
112
"""
113
114
def process_write_fd(self, write_fd: int) -> None:
115
"""
116
Process write events on a file descriptor.
117
118
Args:
119
write_fd: File descriptor ready for writing
120
"""
121
122
def timeout(self, t=None):
123
"""
124
Get or set timeout for next I/O operation.
125
126
Args:
127
t: Optional[float] - Maximum timeout in seconds, or None for no limit
128
129
Returns:
130
float: Actual timeout value for next operation in seconds
131
132
Raises:
133
ValueError: If timeout is negative
134
"""
135
```
136
137
**Usage Example:**
138
139
```python
140
import select
141
import pycares
142
143
def wait_channel(channel):
144
"""Process all pending DNS operations until completion."""
145
while True:
146
read_fds, write_fds = channel.getsock()
147
if not read_fds and not write_fds:
148
break
149
150
timeout = channel.timeout()
151
if timeout == 0.0:
152
# No timeout needed, process immediately
153
channel.process_fd(pycares.ARES_SOCKET_BAD, pycares.ARES_SOCKET_BAD)
154
continue
155
156
# Wait for I/O events
157
rlist, wlist, xlist = select.select(read_fds, write_fds, [], timeout)
158
159
# Process ready file descriptors
160
for fd in rlist:
161
channel.process_read_fd(fd)
162
for fd in wlist:
163
channel.process_write_fd(fd)
164
```
165
166
### Server Configuration
167
168
Manage the list of DNS servers used by the channel for query resolution.
169
170
```python { .api }
171
@property
172
def servers(self) -> list[str]:
173
"""
174
Get the current list of DNS servers.
175
176
Returns:
177
list[str]: List of DNS server IP addresses
178
179
Raises:
180
AresError: If unable to retrieve server list
181
"""
182
183
@servers.setter
184
def servers(self, servers) -> None:
185
"""
186
Set the list of DNS servers for the channel.
187
188
Args:
189
servers: Iterable[Union[str, bytes]] - IP addresses of DNS servers
190
191
Raises:
192
ValueError: If any IP address is invalid
193
AresError: If unable to set servers
194
"""
195
```
196
197
**Usage Example:**
198
199
```python
200
channel = pycares.Channel()
201
202
# Get current servers
203
current_servers = channel.servers
204
print(f"Current servers: {current_servers}")
205
206
# Set new servers
207
channel.servers = ['8.8.8.8', '8.8.4.4', '1.1.1.1']
208
209
# Add IPv6 servers
210
channel.servers = ['2001:4860:4860::8888', '2001:4860:4860::8844']
211
```
212
213
### Channel Control
214
215
Functions for managing channel lifecycle and query operations.
216
217
```python { .api }
218
def cancel(self) -> None:
219
"""
220
Cancel all pending queries on this channel.
221
222
All pending query callbacks will be called with ARES_ECANCELLED error.
223
"""
224
225
def reinit(self) -> None:
226
"""
227
Reinitialize the channel with current system DNS configuration.
228
229
Rereads system DNS settings (resolv.conf, registry, etc.) and applies
230
them to the channel.
231
232
Raises:
233
AresError: If reinitialization fails
234
"""
235
236
def close(self) -> None:
237
"""
238
Close the channel and clean up resources.
239
240
This method schedules safe channel destruction in a background thread.
241
Once called, no new queries can be started. Pending queries will be
242
cancelled and their callbacks will receive ARES_ECANCELLED.
243
244
This method is thread-safe and can be called multiple times.
245
"""
246
```
247
248
### Network Binding
249
250
Configure local network interface binding for outgoing DNS queries.
251
252
```python { .api }
253
def set_local_ip(self, ip) -> None:
254
"""
255
Set the local IP address to bind outgoing queries to.
256
257
Args:
258
ip: Union[str, bytes] - IPv4 or IPv6 address to bind to
259
260
Raises:
261
ValueError: If IP address is invalid
262
"""
263
264
def set_local_dev(self, dev) -> None:
265
"""
266
Set the local network device to bind outgoing queries to.
267
268
Args:
269
dev: str - Network device name (e.g., 'eth0', 'wlan0')
270
"""
271
```
272
273
**Usage Example:**
274
275
```python
276
channel = pycares.Channel()
277
278
# Bind to specific IP address
279
channel.set_local_ip('192.168.1.100')
280
281
# Bind to specific network interface
282
channel.set_local_dev('eth0')
283
284
# Perform queries - they will use the bound interface
285
channel.query('google.com', pycares.QUERY_TYPE_A, callback)
286
```
287
288
## Channel Flags
289
290
Configuration flags that control channel behavior:
291
292
```python { .api }
293
# Use TCP instead of UDP for queries
294
ARES_FLAG_USEVC = 1
295
296
# Only query primary DNS servers
297
ARES_FLAG_PRIMARY = 2
298
299
# Ignore truncated responses
300
ARES_FLAG_IGNTC = 4
301
302
# Don't perform recursive queries
303
ARES_FLAG_NORECURSE = 8
304
305
# Keep TCP connections open for multiple queries
306
ARES_FLAG_STAYOPEN = 16
307
308
# Don't use search domains for single-label names
309
ARES_FLAG_NOSEARCH = 32
310
311
# Don't look up aliases
312
ARES_FLAG_NOALIASES = 64
313
314
# Don't check response against query
315
ARES_FLAG_NOCHECKRESP = 128
316
317
# Enable EDNS (Extension Mechanisms for DNS)
318
ARES_FLAG_EDNS = 256
319
320
# Don't add default servers if none specified
321
ARES_FLAG_NO_DFLT_SVR = 512
322
```
323
324
## Socket State Callback
325
326
For advanced event loop integration, channels can be configured with a socket state callback:
327
328
```python
329
def socket_callback(fd, readable, writable):
330
"""
331
Socket state change callback.
332
333
Args:
334
fd: int - Socket file descriptor
335
readable: bool - Whether socket is ready for reading
336
writable: bool - Whether socket is ready for writing
337
"""
338
if readable:
339
# Add fd to read monitoring
340
loop.add_reader(fd, process_read, fd)
341
if writable:
342
# Add fd to write monitoring
343
loop.add_writer(fd, process_write, fd)
344
if not readable and not writable:
345
# Socket closed, remove from monitoring
346
loop.remove_reader(fd)
347
loop.remove_writer(fd)
348
349
channel = pycares.Channel(sock_state_cb=socket_callback)
350
```
351
352
## Thread Safety
353
354
Check if the underlying c-ares library supports thread-safe operation:
355
356
```python { .api }
357
def ares_threadsafety() -> bool:
358
"""
359
Check if c-ares was compiled with thread safety support.
360
361
Returns:
362
bool: True if thread-safe, False otherwise
363
"""
364
```
365
366
When thread safety is available, you can use `event_thread=True` in Channel constructor to enable built-in event processing without manual I/O monitoring.