or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

channel-management.mddns-queries.mderror-handling.mdhost-resolution.mdindex.mdutilities.md

channel-management.mddocs/

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.