or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

dns-constants.mddns-exceptions.mddns-messages.mddns-names.mddns-queries.mddns-records.mddns-resolution.mddns-updates.mddns-utilities.mddns-zones.mddnssec.mdindex.mdtsig.md

dns-updates.mddocs/

0

# DNS Updates

1

2

Dynamic DNS update functionality for creating and sending DNS UPDATE messages. Provides complete support for adding, deleting, and replacing resource records with optional TSIG authentication.

3

4

## Capabilities

5

6

### Update Message Creation

7

8

Create DNS UPDATE messages for dynamic zone modifications.

9

10

```python { .api }

11

class Update:

12

"""

13

A DNS dynamic update message.

14

15

Represents a DNS UPDATE message that can add, delete, or replace

16

resource records in a DNS zone. Supports prerequisites and

17

TSIG authentication.

18

19

Attributes:

20

zone (dns.name.Name): Zone being updated

21

rdclass (int): Zone class

22

keyring (dict): TSIG keyring for authentication

23

keyname (dns.name.Name): TSIG key name

24

keyalgorithm (dns.name.Name): TSIG algorithm

25

"""

26

27

def __init__(self, zone, rdclass='IN', keyring=None, keyname=None,

28

keyalgorithm='HMAC-MD5.SIG-ALG.REG.INT'):

29

"""

30

Initialize DNS update message.

31

32

Args:

33

zone (str or dns.name.Name): Zone name to update

34

rdclass (str or int): Zone class (default 'IN')

35

keyring (dict): TSIG keyring for authentication

36

keyname (str or dns.name.Name): TSIG key name

37

keyalgorithm (str): TSIG algorithm name

38

"""

39

40

def __str__(self):

41

"""Return string representation of update."""

42

43

def __repr__(self):

44

"""Return detailed string representation."""

45

```

46

47

### Record Addition

48

49

Add resource records to the zone.

50

51

```python { .api }

52

def add(name, *args):

53

"""

54

Add resource records to the zone.

55

56

Args:

57

name (str or dns.name.Name): Record name

58

*args: Variable arguments specifying record data

59

Can be (ttl, rdtype, rdata...) or (rdtype, rdata...)

60

61

Examples:

62

update.add('www.example.com', 300, 'A', '192.0.2.1')

63

update.add('mail', 'MX', 10, 'mail.example.com.')

64

update.add('_sip._tcp', 'SRV', 10, 20, 5060, 'sip.example.com.')

65

"""

66

67

def add_rrset(name, rrset):

68

"""

69

Add an entire RRset to the zone.

70

71

Args:

72

name (str or dns.name.Name): Record name

73

rrset (dns.rrset.RRset): RRset to add

74

"""

75

76

def add_rdataset(name, rdataset):

77

"""

78

Add an rdataset to the zone.

79

80

Args:

81

name (str or dns.name.Name): Record name

82

rdataset (dns.rdataset.Rdataset): Rdataset to add

83

"""

84

```

85

86

### Record Deletion

87

88

Delete resource records from the zone.

89

90

```python { .api }

91

def delete(name, *args):

92

"""

93

Delete resource records from the zone.

94

95

Args:

96

name (str or dns.name.Name): Record name

97

*args: Optional arguments specifying what to delete

98

() - delete all records at name

99

(rdtype) - delete all records of specified type

100

(rdtype, rdata...) - delete specific record

101

102

Examples:

103

update.delete('old.example.com') # Delete all records

104

update.delete('www.example.com', 'A') # Delete all A records

105

update.delete('www.example.com', 'A', '192.0.2.1') # Delete specific A record

106

"""

107

108

def delete_rrset(name, rdtype, covers='NONE'):

109

"""

110

Delete an entire RRset from the zone.

111

112

Args:

113

name (str or dns.name.Name): Record name

114

rdtype (str or int): Record type to delete

115

covers (str or int): Covered type for RRSIG records

116

"""

117

118

def delete_rdataset(name, rdataset):

119

"""

120

Delete specific rdataset from the zone.

121

122

Args:

123

name (str or dns.name.Name): Record name

124

rdataset (dns.rdataset.Rdataset): Rdataset to delete

125

"""

126

```

127

128

### Record Replacement

129

130

Replace existing resource records in the zone.

131

132

```python { .api }

133

def replace(name, *args):

134

"""

135

Replace resource records in the zone.

136

137

Deletes all existing records of the specified type and adds new ones.

138

139

Args:

140

name (str or dns.name.Name): Record name

141

*args: Arguments specifying replacement records

142

Format: (ttl, rdtype, rdata...) or (rdtype, rdata...)

143

144

Examples:

145

update.replace('www.example.com', 300, 'A', '192.0.2.10')

146

update.replace('mail', 'MX', 10, 'mail1.example.com.', 20, 'mail2.example.com.')

147

"""

148

149

def replace_rrset(name, rrset):

150

"""

151

Replace an RRset in the zone.

152

153

Args:

154

name (str or dns.name.Name): Record name

155

rrset (dns.rrset.RRset): Replacement RRset

156

"""

157

158

def replace_rdataset(name, rdataset):

159

"""

160

Replace an rdataset in the zone.

161

162

Args:

163

name (str or dns.name.Name): Record name

164

rdataset (dns.rdataset.Rdataset): Replacement rdataset

165

"""

166

```

167

168

### Prerequisites

169

170

Set prerequisites that must be satisfied for the update to succeed.

171

172

```python { .api }

173

def present(name, *args):

174

"""

175

Specify that records must be present for update to succeed.

176

177

Args:

178

name (str or dns.name.Name): Record name

179

*args: Optional arguments specifying what must be present

180

() - name must exist (any record type)

181

(rdtype) - name must have records of specified type

182

(rdtype, rdata...) - specific record must exist

183

184

Examples:

185

update.present('www.example.com') # Name must exist

186

update.present('www.example.com', 'A') # Must have A records

187

update.present('www.example.com', 'A', '192.0.2.1') # Specific A record must exist

188

"""

189

190

def absent(name, *args):

191

"""

192

Specify that records must be absent for update to succeed.

193

194

Args:

195

name (str or dns.name.Name): Record name

196

*args: Optional arguments specifying what must be absent

197

() - name must not exist (no records of any type)

198

(rdtype) - name must not have records of specified type

199

(rdtype, rdata...) - specific record must not exist

200

201

Examples:

202

update.absent('new.example.com') # Name must not exist

203

update.absent('www.example.com', 'AAAA') # Must not have AAAA records

204

update.absent('www.example.com', 'A', '192.0.2.99') # Specific A record must not exist

205

"""

206

```

207

208

### Update Execution

209

210

Send update messages to nameservers.

211

212

```python { .api }

213

def to_wire(self):

214

"""

215

Convert update message to wire format.

216

217

Returns:

218

bytes: Wire format update message

219

"""

220

221

def __call__(self, nameserver, timeout=None, port=53, af=None, source=None, source_port=0):

222

"""

223

Send the update to a nameserver (callable interface).

224

225

Args:

226

nameserver (str): Nameserver IP address

227

timeout (float): Query timeout

228

port (int): Destination port (default 53)

229

af (int): Address family

230

source (str): Source IP address

231

source_port (int): Source port

232

233

Returns:

234

dns.message.Message: Response message

235

"""

236

```

237

238

## Usage Examples

239

240

### Basic Record Updates

241

242

```python

243

import dns.update

244

import dns.query

245

import dns.rdatatype

246

247

# Create update message

248

zone = 'example.com.'

249

update = dns.update.Update(zone)

250

251

# Add records

252

update.add('www.example.com.', 300, 'A', '192.0.2.10')

253

update.add('www.example.com.', 300, 'AAAA', '2001:db8::10')

254

update.add('mail.example.com.', 300, 'A', '192.0.2.20')

255

256

# Add MX record

257

update.add('example.com.', 300, 'MX', 10, 'mail.example.com.')

258

259

# Send update

260

nameserver = '192.0.2.1' # Authoritative nameserver

261

response = dns.query.tcp(update, nameserver)

262

263

if response.rcode() == dns.rcode.NOERROR:

264

print("Update successful")

265

else:

266

print(f"Update failed: {dns.rcode.to_text(response.rcode())}")

267

```

268

269

### Record Deletion and Replacement

270

271

```python

272

import dns.update

273

274

update = dns.update.Update('example.com.')

275

276

# Delete specific record

277

update.delete('old.example.com.', 'A', '192.0.2.99')

278

279

# Delete all A records at name

280

update.delete('www.example.com.', 'A')

281

282

# Delete all records at name

283

update.delete('obsolete.example.com.')

284

285

# Replace all A records

286

update.replace('www.example.com.', 300, 'A', '192.0.2.100')

287

288

# Replace MX records

289

update.replace('example.com.', 300, 'MX', 10, 'mail1.example.com.', 20, 'mail2.example.com.')

290

291

# Send update

292

response = dns.query.tcp(update, '192.0.2.1')

293

```

294

295

### Updates with Prerequisites

296

297

```python

298

import dns.update

299

300

update = dns.update.Update('example.com.')

301

302

# Only proceed if www.example.com has specific A record

303

update.present('www.example.com.', 'A', '192.0.2.1')

304

305

# Replace it with new address

306

update.replace('www.example.com.', 300, 'A', '192.0.2.10')

307

308

# Only proceed if new.example.com doesn't exist

309

update.absent('new.example.com.')

310

311

# Add new record

312

update.add('new.example.com.', 300, 'A', '192.0.2.50')

313

314

# Send conditional update

315

response = dns.query.tcp(update, '192.0.2.1')

316

```

317

318

### Authenticated Updates with TSIG

319

320

```python

321

import dns.update

322

import dns.tsigkeyring

323

import dns.query

324

325

# Create TSIG keyring

326

keyring = dns.tsigkeyring.from_text({

327

'update-key.example.com.': 'base64-encoded-key-data'

328

})

329

330

# Create authenticated update

331

update = dns.update.Update(

332

'example.com.',

333

keyring=keyring,

334

keyname='update-key.example.com.'

335

)

336

337

# Add records

338

update.add('secure.example.com.', 300, 'A', '192.0.2.100')

339

update.add('secure.example.com.', 300, 'TXT', 'Updated via authenticated TSIG')

340

341

# Send authenticated update

342

response = dns.query.tcp(update, '192.0.2.1')

343

344

if response.rcode() == dns.rcode.NOERROR:

345

print("Authenticated update successful")

346

347

# Verify TSIG authentication

348

if response.had_tsig():

349

if response.tsig_error() == 0:

350

print("TSIG verification successful")

351

else:

352

print(f"TSIG error: {response.tsig_error()}")

353

else:

354

print(f"Update failed: {dns.rcode.to_text(response.rcode())}")

355

```

356

357

### Complex Service Record Updates

358

359

```python

360

import dns.update

361

362

update = dns.update.Update('example.com.')

363

364

# Add SRV records for SIP service

365

update.add('_sip._tcp.example.com.', 300, 'SRV', 10, 20, 5060, 'sip1.example.com.')

366

update.add('_sip._tcp.example.com.', 300, 'SRV', 10, 30, 5060, 'sip2.example.com.')

367

update.add('_sip._tcp.example.com.', 300, 'SRV', 20, 10, 5060, 'sip3.example.com.')

368

369

# Add corresponding A records

370

update.add('sip1.example.com.', 300, 'A', '192.0.2.11')

371

update.add('sip2.example.com.', 300, 'A', '192.0.2.12')

372

update.add('sip3.example.com.', 300, 'A', '192.0.2.13')

373

374

# Add NAPTR record for service discovery

375

update.add('example.com.', 300, 'NAPTR', 100, 10, 'u', 'E2U+sip',

376

'!^.*$!sip:info@example.com!', '.')

377

378

# Send update

379

response = dns.query.tcp(update, '192.0.2.1')

380

```

381

382

### Batch Updates

383

384

```python

385

import dns.update

386

import dns.rrset

387

import dns.rdata

388

import dns.rdatatype

389

import dns.rdataclass

390

391

update = dns.update.Update('example.com.')

392

393

# Create RRsets for batch operations

394

www_rrset = dns.rrset.RRset(dns.name.from_text('www.example.com.'),

395

dns.rdataclass.IN, dns.rdatatype.A)

396

www_rrset.add(dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'), ttl=300)

397

www_rrset.add(dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.2'), ttl=300)

398

399

# Add entire RRset

400

update.add_rrset('www.example.com.', www_rrset)

401

402

# Create and add MX RRset

403

mx_rrset = dns.rrset.from_text('example.com.', 300, 'IN', 'MX',

404

'10 mail1.example.com.', '20 mail2.example.com.')

405

update.add_rrset('example.com.', mx_rrset)

406

407

# Send batch update

408

response = dns.query.tcp(update, '192.0.2.1')

409

```

410

411

### Error Handling

412

413

```python

414

import dns.update

415

import dns.query

416

import dns.rcode

417

import dns.exception

418

419

try:

420

update = dns.update.Update('example.com.')

421

update.add('test.example.com.', 300, 'A', '192.0.2.50')

422

423

response = dns.query.tcp(update, '192.0.2.1', timeout=10)

424

425

rcode = response.rcode()

426

if rcode == dns.rcode.NOERROR:

427

print("Update completed successfully")

428

elif rcode == dns.rcode.REFUSED:

429

print("Update refused - check authorization")

430

elif rcode == dns.rcode.NOTAUTH:

431

print("Server not authoritative for zone")

432

elif rcode == dns.rcode.YXDOMAIN:

433

print("Prerequisites failed - domain exists when it shouldn't")

434

elif rcode == dns.rcode.NXDOMAIN:

435

print("Prerequisites failed - domain doesn't exist when it should")

436

elif rcode == dns.rcode.YXRRSET:

437

print("Prerequisites failed - RRset exists when it shouldn't")

438

elif rcode == dns.rcode.NXRRSET:

439

print("Prerequisites failed - RRset doesn't exist when it should")

440

else:

441

print(f"Update failed with rcode: {dns.rcode.to_text(rcode)}")

442

443

except dns.exception.Timeout:

444

print("Update timed out")

445

except dns.tsig.BadSignature:

446

print("TSIG signature verification failed")

447

except dns.exception.DNSException as e:

448

print(f"DNS error: {e}")

449

```

450

451

## Update Response Codes

452

453

```python { .api }

454

# Standard response codes relevant to updates

455

NOERROR = 0 # No error - update successful

456

FORMERR = 1 # Format error in update message

457

SERVFAIL = 2 # Server failure

458

NXDOMAIN = 3 # Name does not exist (prerequisite)

459

NOTIMP = 4 # Not implemented

460

REFUSED = 5 # Update refused

461

YXDOMAIN = 6 # Name exists when it should not (prerequisite)

462

YXRRSET = 7 # RRset exists when it should not (prerequisite)

463

NXRRSET = 8 # RRset does not exist when it should (prerequisite)

464

NOTAUTH = 9 # Server not authoritative for zone

465

NOTZONE = 10 # Name not contained in zone

466

```

467

468

## Integration with Other Modules

469

470

DNS Updates work seamlessly with other dnspython modules:

471

472

- **TSIG Authentication**: Use `dns.tsig` and `dns.tsigkeyring` for secure updates

473

- **Record Creation**: Use `dns.rdata` and `dns.rrset` for complex record structures

474

- **Name Handling**: Use `dns.name` for proper name formatting and validation

475

- **Message Transport**: Use `dns.query` for sending updates via UDP or TCP

476

- **Response Handling**: Use `dns.message` for processing update responses