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-messages.mddocs/

0

# DNS Messages

1

2

DNS message manipulation functionality for creating, parsing, and modifying DNS protocol messages. Provides complete control over DNS message structure including headers, questions, answers, authority, and additional sections.

3

4

## Capabilities

5

6

### Message Creation

7

8

Create DNS query and response messages with full protocol support.

9

10

```python { .api }

11

def make_query(qname, rdtype, rdclass='IN', use_edns=None, want_dnssec=False,

12

ednsflags=None, payload=None, request_payload=None, options=None):

13

"""

14

Create a DNS query message.

15

16

Args:

17

qname (str or dns.name.Name): Query name

18

rdtype (str or int): Record type to query

19

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

20

use_edns (int): EDNS version (None to disable, 0 for EDNS0)

21

want_dnssec (bool): Set DNSSEC OK bit

22

ednsflags (int): EDNS flags

23

payload (int): EDNS payload size

24

request_payload (int): Requested payload size

25

options (list): EDNS options

26

27

Returns:

28

dns.message.Message: DNS query message

29

"""

30

31

def make_response(query, recursion_available=False, our_payload=8192, fudge=300):

32

"""

33

Create a DNS response message from a query.

34

35

Args:

36

query (dns.message.Message): Original query message

37

recursion_available (bool): Set RA bit

38

our_payload (int): Our EDNS payload size

39

fudge (int): TSIG time fudge factor

40

41

Returns:

42

dns.message.Message: DNS response message

43

"""

44

```

45

46

### Message Parsing

47

48

Parse DNS messages from wire format, text format, or files.

49

50

```python { .api }

51

def from_wire(wire, keyring=None, request_mac=b'', xfr=False, origin=None,

52

tsig_ctx=None, multi=False, first=True, question_only=False,

53

one_rr_per_rrset=False, ignore_trailing=False):

54

"""

55

Parse a DNS message from wire format.

56

57

Args:

58

wire (bytes): Wire format message

59

keyring (dict): TSIG keyring for validation

60

request_mac (bytes): TSIG MAC from request

61

xfr (bool): Message is part of zone transfer

62

origin (dns.name.Name): Origin for relative names

63

tsig_ctx (dns.tsig.HMACTSig): TSIG context

64

multi (bool): Message is part of multi-message response

65

first (bool): First message in multi-message response

66

question_only (bool): Parse question section only

67

one_rr_per_rrset (bool): Put each RR in its own RRset

68

ignore_trailing (bool): Ignore trailing junk

69

70

Returns:

71

dns.message.Message: Parsed DNS message

72

"""

73

74

def from_text(text):

75

"""

76

Parse a DNS message from text format.

77

78

Args:

79

text (str): Text format message

80

81

Returns:

82

dns.message.Message: Parsed DNS message

83

"""

84

85

def from_file(f):

86

"""

87

Read and parse a DNS message from a file.

88

89

Args:

90

f (file-like): File to read from

91

92

Returns:

93

dns.message.Message: Parsed DNS message

94

"""

95

```

96

97

### Message Class

98

99

Complete DNS message with header and sections for questions, answers, authority, and additional records.

100

101

```python { .api }

102

class Message:

103

"""

104

A DNS message with header and sections.

105

106

Attributes:

107

id (int): Message ID

108

flags (int): Header flags

109

question (list): Question section

110

answer (list): Answer section

111

authority (list): Authority section

112

additional (list): Additional section

113

opt (dns.edns.OPT): EDNS OPT record

114

tsig (dns.rdata.Rdata): TSIG record

115

request_payload (int): Requested EDNS payload size

116

keyring (dict): TSIG keyring

117

mac (bytes): TSIG MAC

118

xfr (bool): Message is part of zone transfer

119

origin (dns.name.Name): Origin for relative names

120

tsig_ctx (dns.tsig.HMACTSig): TSIG context

121

"""

122

123

def __init__(self, id=None):

124

"""

125

Initialize DNS message.

126

127

Args:

128

id (int): Message ID (random if None)

129

"""

130

131

def __repr__(self):

132

"""Return string representation of message."""

133

134

def __str__(self):

135

"""Return string representation of message."""

136

137

def to_wire(self, origin=None, max_size=0, **kw):

138

"""

139

Convert message to wire format.

140

141

Args:

142

origin (dns.name.Name): Origin for relative names

143

max_size (int): Maximum message size

144

**kw: Additional options

145

146

Returns:

147

bytes: Wire format message

148

"""

149

150

def to_text(self, origin=None, relativize=True, **kw):

151

"""

152

Convert message to text format.

153

154

Args:

155

origin (dns.name.Name): Origin for relative names

156

relativize (bool): Relativize names to origin

157

**kw: Additional options

158

159

Returns:

160

str: Text format message

161

"""

162

163

def is_response(self, other):

164

"""

165

Check if this message is a response to another message.

166

167

Args:

168

other (dns.message.Message): Potential query message

169

170

Returns:

171

bool: True if this is a response to other

172

"""

173

174

def is_valid_response(self):

175

"""

176

Check if message is a valid response.

177

178

Returns:

179

bool: True if valid response

180

"""

181

```

182

183

### Message Section Operations

184

185

Find, get, and manipulate RRsets within message sections.

186

187

```python { .api }

188

def find_rrset(section, name, rdclass, rdtype, covers='NONE', deleting=None,

189

create=False, force_unique=False):

190

"""

191

Find an RRset in the specified message section.

192

193

Args:

194

section (int): Message section (QUESTION, ANSWER, AUTHORITY, ADDITIONAL)

195

name (dns.name.Name): Record name

196

rdclass (int): Record class

197

rdtype (int): Record type

198

covers (int): Covered type for RRSIG records

199

deleting (int): Deletion indicator for dynamic updates

200

create (bool): Create RRset if not found

201

force_unique (bool): Force unique names

202

203

Returns:

204

dns.rrset.RRset: Found or created RRset

205

"""

206

207

def get_rrset(section, name, rdclass, rdtype, covers='NONE', deleting=None,

208

create=False, force_unique=False):

209

"""

210

Get an RRset from the specified message section.

211

212

Args:

213

section (int): Message section

214

name (dns.name.Name): Record name

215

rdclass (int): Record class

216

rdtype (int): Record type

217

covers (int): Covered type for RRSIG records

218

deleting (int): Deletion indicator

219

create (bool): Create RRset if not found

220

force_unique (bool): Force unique names

221

222

Returns:

223

dns.rrset.RRset or None: Found RRset or None

224

"""

225

```

226

227

### EDNS and TSIG Configuration

228

229

Configure extended DNS (EDNS) and transaction signatures (TSIG) for messages.

230

231

```python { .api }

232

def use_edns(edns=0, ednsflags=0, payload=1280, request_payload=None, options=None):

233

"""

234

Configure EDNS for this message.

235

236

Args:

237

edns (int): EDNS version (0 for EDNS0, -1 to disable)

238

ednsflags (int): EDNS flags

239

payload (int): Payload size

240

request_payload (int): Requested payload size

241

options (list): EDNS options

242

"""

243

244

def use_tsig(keyring, keyname=None, fudge=300, original_id=None, tsig_error=0,

245

other_data=b'', algorithm='HMAC-MD5.SIG-ALG.REG.INT'):

246

"""

247

Configure TSIG for this message.

248

249

Args:

250

keyring (dict): TSIG keyring

251

keyname (dns.name.Name): Key name

252

fudge (int): Time fudge factor

253

original_id (int): Original message ID

254

tsig_error (int): TSIG error code

255

other_data (bytes): Additional TSIG data

256

algorithm (str): TSIG algorithm name

257

"""

258

259

def want_dnssec(wanted=True):

260

"""

261

Enable or disable DNSSEC DO bit.

262

263

Args:

264

wanted (bool): Enable DNSSEC

265

"""

266

```

267

268

### Message Properties

269

270

Access message header fields and computed properties.

271

272

```python { .api }

273

def id():

274

"""Get message ID."""

275

276

def flags():

277

"""Get header flags."""

278

279

def rcode():

280

"""Get response code."""

281

282

def opcode():

283

"""Get operation code."""

284

285

def question_for_answer():

286

"""Get question corresponding to first answer."""

287

288

def had_tsig():

289

"""Check if message had TSIG."""

290

291

def tsig_error():

292

"""Get TSIG error code."""

293

294

def mac():

295

"""Get TSIG MAC."""

296

```

297

298

## Usage Examples

299

300

### Creating Query Messages

301

302

```python

303

import dns.message

304

import dns.name

305

import dns.rdatatype

306

307

# Basic query

308

qname = dns.name.from_text('example.com')

309

query = dns.message.make_query(qname, dns.rdatatype.A)

310

311

# Query with EDNS and DNSSEC

312

query_edns = dns.message.make_query(

313

qname, dns.rdatatype.DNSKEY,

314

use_edns=0,

315

want_dnssec=True,

316

payload=4096

317

)

318

319

# Multiple questions (not common but supported)

320

query = dns.message.Message()

321

query.id = dns.entropy.random_16()

322

query.flags = dns.flags.RD # Recursion desired

323

query.find_rrset(dns.message.QUESTION, qname, dns.rdataclass.IN,

324

dns.rdatatype.A, create=True)

325

```

326

327

### Parsing Wire Format

328

329

```python

330

import dns.message

331

332

# Parse raw DNS packet

333

wire_data = b'\x12\x34\x01\x00...' # Raw DNS packet bytes

334

message = dns.message.from_wire(wire_data)

335

336

print(f"Message ID: {message.id}")

337

print(f"Response code: {message.rcode()}")

338

print(f"Question count: {len(message.question)}")

339

print(f"Answer count: {len(message.answer)}")

340

341

# Process answers

342

for rrset in message.answer:

343

print(f"Name: {rrset.name}")

344

print(f"Type: {rrset.rdtype}")

345

for rdata in rrset:

346

print(f" Data: {rdata}")

347

```

348

349

### Creating Response Messages

350

351

```python

352

import dns.message

353

import dns.rrset

354

import dns.rdata

355

import dns.rdataclass

356

import dns.rdatatype

357

358

# Create response from query

359

query = dns.message.make_query('example.com', dns.rdatatype.A)

360

response = dns.message.make_response(query, recursion_available=True)

361

362

# Add answer records

363

answer_rrset = dns.rrset.from_text('example.com', 300, 'IN', 'A', '192.0.2.1')

364

response.answer.append(answer_rrset)

365

366

# Set response code

367

response.set_rcode(dns.rcode.NOERROR)

368

369

# Convert to wire format for transmission

370

wire_response = response.to_wire()

371

```

372

373

### Working with Message Sections

374

375

```python

376

import dns.message

377

import dns.name

378

import dns.rdatatype

379

import dns.rdataclass

380

381

message = dns.message.from_wire(wire_data)

382

383

# Find specific RRset

384

name = dns.name.from_text('example.com')

385

rrset = message.find_rrset(dns.message.ANSWER, name,

386

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

387

388

if rrset:

389

print(f"Found {len(rrset)} A records for {name}")

390

for rdata in rrset:

391

print(f" {rdata.address}")

392

393

# Check all sections

394

sections = [

395

(dns.message.QUESTION, message.question, "Question"),

396

(dns.message.ANSWER, message.answer, "Answer"),

397

(dns.message.AUTHORITY, message.authority, "Authority"),

398

(dns.message.ADDITIONAL, message.additional, "Additional")

399

]

400

401

for section_id, section_list, section_name in sections:

402

print(f"{section_name} section: {len(section_list)} RRsets")

403

```

404

405

## Constants

406

407

```python { .api }

408

# Message sections

409

QUESTION = 0

410

ANSWER = 1

411

AUTHORITY = 2

412

ADDITIONAL = 3

413

414

# Header flags

415

QR = 0x8000 # Query/Response

416

AA = 0x0400 # Authoritative Answer

417

TC = 0x0200 # Truncated

418

RD = 0x0100 # Recursion Desired

419

RA = 0x0080 # Recursion Available

420

AD = 0x0020 # Authentic Data

421

CD = 0x0010 # Checking Disabled

422

```

423

424

## Exceptions

425

426

```python { .api }

427

class ShortHeader(DNSException):

428

"""A DNS packet is too short to contain a complete header."""

429

430

class TrailingJunk(DNSException):

431

"""There is trailing junk after the end of the DNS message."""

432

433

class UnknownHeaderField(DNSException):

434

"""An unknown header field name was specified."""

435

436

class BadEDNS(DNSException):

437

"""An OPT record was found somewhere other than the additional section."""

438

439

class BadTSIG(DNSException):

440

"""A TSIG record was found somewhere other than the end of the additional section."""

441

442

class UnknownTSIGKey(DNSException):

443

"""A TSIG record was received with an unknown key."""

444

```