or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

dns-client.mddns-core.mddns-records.mddns-resolvers.mddns-server.mddns-utils.mdindex.md

dns-core.mddocs/

0

# DNS Core Functionality

1

2

Core DNS packet encoding, decoding, and manipulation functionality that forms the foundation of dnslib. Handles conversion between wire format, Python objects, and Zone/DiG textual representations.

3

4

## Capabilities

5

6

### DNS Record Container

7

8

Main container class for complete DNS packets with header, questions, answers, authority, and additional sections.

9

10

```python { .api }

11

class DNSRecord:

12

"""

13

DNS packet container with header and resource record sections.

14

15

Args:

16

header (DNSHeader, optional): DNS packet header

17

q (DNSQuestion or list, optional): Question section entries

18

a (RR or list, optional): Answer section entries

19

auth (RR or list, optional): Authority section entries

20

ar (RR or list, optional): Additional section entries

21

"""

22

def __init__(self, header=None, q=None, a=None, auth=None, ar=None): ...

23

24

@classmethod

25

def parse(cls, packet):

26

"""

27

Parse DNS packet from wire format bytes.

28

29

Args:

30

packet (bytes): DNS packet in wire format

31

32

Returns:

33

DNSRecord: Parsed DNS record object

34

35

Raises:

36

DNSError: If packet is malformed

37

"""

38

39

@classmethod

40

def question(cls, qname, qtype="A", qclass="IN"):

41

"""

42

Create DNS query packet.

43

44

Args:

45

qname (str): Domain name to query

46

qtype (str or int, optional): Query type (default: "A")

47

qclass (str or int, optional): Query class (default: "IN")

48

49

Returns:

50

DNSRecord: DNS query packet

51

"""

52

53

def pack(self):

54

"""

55

Pack DNS record to wire format bytes.

56

57

Returns:

58

bytes: DNS packet in wire format

59

"""

60

61

def reply(self, ra=1, aa=1):

62

"""

63

Create reply packet based on this query.

64

65

Args:

66

ra (int, optional): Recursion available flag (default: 1)

67

aa (int, optional): Authoritative answer flag (default: 1)

68

69

Returns:

70

DNSRecord: DNS response packet

71

"""

72

73

def replyZone(self, zone):

74

"""

75

Create reply packet from zone file format string.

76

77

Args:

78

zone (str): Zone file format resource records

79

80

Returns:

81

DNSRecord: DNS response packet with zone data

82

"""

83

84

def add_question(self, q):

85

"""Add question to question section."""

86

87

def add_answer(self, *rr):

88

"""Add resource records to answer section."""

89

90

def add_auth(self, *rr):

91

"""Add resource records to authority section."""

92

93

def add_ar(self, *rr):

94

"""Add resource records to additional section."""

95

96

def send(self, dest, port=53, tcp=False, timeout=None, ipv6=False):

97

"""

98

Send DNS query and return response.

99

100

Args:

101

dest (str): Destination server address

102

port (int, optional): Destination port (default: 53)

103

tcp (bool, optional): Use TCP instead of UDP (default: False)

104

timeout (int, optional): Query timeout in seconds (default: None)

105

ipv6 (bool, optional): Use IPv6 (default: False)

106

107

Returns:

108

bytes: DNS response packet in wire format

109

"""

110

111

def format(self, prefix="", sort=False):

112

"""

113

Format DNS record as string with optional prefix and sorting.

114

115

Args:

116

prefix (str, optional): Prefix for each line

117

sort (bool, optional): Sort resource records

118

119

Returns:

120

str: Formatted DNS record

121

"""

122

123

def toZone(self, prefix=""):

124

"""

125

Convert DNS record to zone file format.

126

127

Args:

128

prefix (str, optional): Prefix for each line

129

130

Returns:

131

str: Zone file format string

132

"""

133

134

def short(self):

135

"""

136

Return short string representation of DNS record.

137

138

Returns:

139

str: Short format string

140

"""

141

142

def diff(self, other):

143

"""

144

Compare DNS records and return differences.

145

146

Args:

147

other (DNSRecord): Other DNS record to compare

148

149

Returns:

150

str: Difference description

151

"""

152

153

def truncate(self):

154

"""

155

Truncate DNS record by removing additional and authority sections.

156

Sets TC flag in header.

157

"""

158

159

def set_header_qa(self):

160

"""Update header question/answer counts from sections."""

161

```

162

163

### DNS Header

164

165

DNS packet header containing ID, flags, and section counts.

166

167

```python { .api }

168

class DNSHeader:

169

"""

170

DNS packet header with ID, flags, and section record counts.

171

172

Args:

173

id (int, optional): Transaction ID (random if not specified)

174

qr (int, optional): Query/Response flag (0=query, 1=response)

175

opcode (int, optional): Operation code (0=QUERY, 1=IQUERY, etc.)

176

aa (int, optional): Authoritative answer flag

177

tc (int, optional): Truncation flag

178

rd (int, optional): Recursion desired flag

179

ra (int, optional): Recursion available flag

180

z (int, optional): Reserved bits (must be 0)

181

ad (int, optional): Authentic data flag (DNSSEC)

182

cd (int, optional): Checking disabled flag (DNSSEC)

183

rcode (int, optional): Response code (0=NOERROR, 3=NXDOMAIN, etc.)

184

q (int, optional): Question count

185

a (int, optional): Answer count

186

auth (int, optional): Authority count

187

ar (int, optional): Additional count

188

"""

189

def __init__(self, id=None, **kwargs): ...

190

191

def pack(self):

192

"""

193

Pack header to wire format bytes.

194

195

Returns:

196

bytes: Header in wire format

197

"""

198

199

@classmethod

200

def parse(cls, buffer):

201

"""

202

Parse header from wire format buffer.

203

204

Args:

205

buffer (Buffer): Wire format buffer

206

207

Returns:

208

DNSHeader: Parsed header object

209

"""

210

211

def toZone(self):

212

"""

213

Convert header to zone file format comment.

214

215

Returns:

216

str: Zone file format header comment

217

"""

218

219

# Properties for flag access

220

@property

221

def qr(self):

222

"""Query/Response flag (0=query, 1=response)."""

223

224

@qr.setter

225

def qr(self, value):

226

"""Set Query/Response flag."""

227

228

@property

229

def opcode(self):

230

"""Operation code (QUERY, IQUERY, STATUS, etc.)."""

231

232

@opcode.setter

233

def opcode(self, value):

234

"""Set operation code."""

235

236

@property

237

def aa(self):

238

"""Authoritative Answer flag."""

239

240

@aa.setter

241

def aa(self, value):

242

"""Set Authoritative Answer flag."""

243

244

@property

245

def tc(self):

246

"""Truncation flag."""

247

248

@tc.setter

249

def tc(self, value):

250

"""Set Truncation flag."""

251

252

@property

253

def rd(self):

254

"""Recursion Desired flag."""

255

256

@rd.setter

257

def rd(self, value):

258

"""Set Recursion Desired flag."""

259

260

@property

261

def ra(self):

262

"""Recursion Available flag."""

263

264

@ra.setter

265

def ra(self, value):

266

"""Set Recursion Available flag."""

267

268

@property

269

def z(self):

270

"""Reserved bits (must be 0)."""

271

272

@z.setter

273

def z(self, value):

274

"""Set reserved bits."""

275

276

@property

277

def ad(self):

278

"""Authentic Data flag (DNSSEC)."""

279

280

@ad.setter

281

def ad(self, value):

282

"""Set Authentic Data flag."""

283

284

@property

285

def cd(self):

286

"""Checking Disabled flag (DNSSEC)."""

287

288

@cd.setter

289

def cd(self, value):

290

"""Set Checking Disabled flag."""

291

292

@property

293

def rcode(self):

294

"""Response code (NOERROR, NXDOMAIN, etc.)."""

295

296

@rcode.setter

297

def rcode(self, value):

298

"""Set response code."""

299

```

300

301

### DNS Question

302

303

DNS question section specifying query name, type, and class.

304

305

```python { .api }

306

class DNSQuestion:

307

"""

308

DNS question entry specifying query parameters.

309

310

Args:

311

qname (str or DNSLabel): Domain name to query

312

qtype (str or int, optional): Query type (default: "A")

313

qclass (str or int, optional): Query class (default: "IN")

314

"""

315

def __init__(self, qname, qtype="A", qclass="IN"): ...

316

317

def pack(self):

318

"""

319

Pack question to wire format bytes.

320

321

Returns:

322

bytes: Question in wire format

323

"""

324

325

@classmethod

326

def parse(cls, buffer):

327

"""

328

Parse question from wire format buffer.

329

330

Args:

331

buffer (Buffer): Wire format buffer

332

333

Returns:

334

DNSQuestion: Parsed question object

335

"""

336

```

337

338

### Resource Record

339

340

DNS resource record containing name, type, class, TTL, and resource data.

341

342

```python { .api }

343

class RR:

344

"""

345

DNS resource record with header and resource data.

346

347

Args:

348

rname (str or DNSLabel): Resource record name

349

rtype (str or int, optional): Record type (default: "A")

350

rclass (str or int, optional): Record class (default: "IN")

351

ttl (int, optional): Time to live in seconds (default: 0)

352

rdata (RD object, optional): Resource data

353

"""

354

def __init__(self, rname, rtype="A", rclass="IN", ttl=0, rdata=None): ...

355

356

def pack(self):

357

"""

358

Pack resource record to wire format bytes.

359

360

Returns:

361

bytes: Resource record in wire format

362

"""

363

364

@classmethod

365

def parse(cls, buffer):

366

"""

367

Parse resource record from wire format buffer.

368

369

Args:

370

buffer (Buffer): Wire format buffer

371

372

Returns:

373

RR: Parsed resource record object

374

"""

375

376

@classmethod

377

def fromZone(cls, zone, origin=None, ttl=None):

378

"""

379

Parse resource records from zone file format string.

380

381

Args:

382

zone (str): Zone file format string

383

origin (str, optional): Default origin domain

384

ttl (int, optional): Default TTL value

385

386

Returns:

387

list[RR]: List of parsed resource records

388

"""

389

```

390

391

### DNS Labels

392

393

DNS name representation with IDNA encoding support and label manipulation.

394

395

```python { .api }

396

class DNSLabel:

397

"""

398

DNS label with IDNA encoding support.

399

400

Args:

401

label (str or list): Domain name string or label components

402

"""

403

def __init__(self, label): ...

404

405

def encode(self):

406

"""

407

Encode label to wire format bytes.

408

409

Returns:

410

bytes: Encoded label

411

"""

412

413

@classmethod

414

def decode(cls, buffer):

415

"""

416

Decode label from wire format buffer.

417

418

Args:

419

buffer (Buffer): Wire format buffer

420

421

Returns:

422

DNSLabel: Decoded label object

423

"""

424

425

def idna(self):

426

"""

427

Convert label to IDNA format.

428

429

Returns:

430

DNSLabel: IDNA encoded label

431

"""

432

433

def matchSuffix(self, suffix):

434

"""

435

Check if label ends with suffix (case-insensitive).

436

437

Args:

438

suffix (str or DNSLabel): Suffix to match

439

440

Returns:

441

bool: True if label ends with suffix

442

"""

443

444

def stripSuffix(self, suffix):

445

"""

446

Remove suffix from label (case-insensitive).

447

448

Args:

449

suffix (str or DNSLabel): Suffix to remove

450

451

Returns:

452

DNSLabel: Label with suffix removed

453

"""

454

455

def matchWildcard(self, pattern):

456

"""

457

Match label against wildcard pattern.

458

459

Args:

460

pattern (str or DNSLabel): Wildcard pattern (* supported)

461

462

Returns:

463

bool: True if label matches pattern

464

"""

465

```

466

467

### EDNS0 Support

468

469

Extended DNS (EDNS0) support for larger packets and options.

470

471

```python { .api }

472

class EDNS0:

473

"""

474

EDNS0 (Extended DNS) pseudo-record for enhanced DNS functionality.

475

476

Args:

477

version (int, optional): EDNS version (default: 0)

478

flags (str or int, optional): EDNS flags ("do" for DNSSEC OK)

479

udp_len (int, optional): UDP payload size (default: 4096)

480

rcode_ext (int, optional): Extended response code

481

options (list, optional): EDNS options

482

"""

483

def __init__(self, version=0, flags=0, udp_len=4096, rcode_ext=0, options=None): ...

484

485

def pack(self):

486

"""Pack EDNS0 record to wire format."""

487

488

@classmethod

489

def parse(cls, buffer):

490

"""Parse EDNS0 record from wire format buffer."""

491

```

492

493

### EDNS Options

494

495

EDNS option handling for extended functionality.

496

497

```python { .api }

498

class EDNSOption:

499

"""

500

EDNS option for extended DNS functionality.

501

502

Args:

503

code (int): Option code

504

data (bytes): Option data

505

"""

506

def __init__(self, code, data): ...

507

508

def pack(self):

509

"""Pack option to wire format."""

510

511

@classmethod

512

def parse(cls, buffer):

513

"""Parse option from wire format buffer."""

514

```

515

516

### Buffer Management

517

518

Core buffer functionality for wire format packet handling.

519

520

```python { .api }

521

class Buffer:

522

"""

523

Simple data buffer with pack/unpack support for binary data manipulation.

524

525

Args:

526

data (bytes, optional): Initial buffer data

527

"""

528

def __init__(self, data=b""): ...

529

530

def remaining(self):

531

"""

532

Get remaining bytes in buffer.

533

534

Returns:

535

int: Number of remaining bytes

536

"""

537

538

def get(self, length):

539

"""

540

Get specified number of bytes from buffer.

541

542

Args:

543

length (int): Number of bytes to read

544

545

Returns:

546

bytes: Buffer data

547

"""

548

549

def pack(self, fmt, *args):

550

"""

551

Pack data using struct format and append to buffer.

552

553

Args:

554

fmt (str): Struct format string

555

*args: Values to pack

556

"""

557

558

def append(self, data):

559

"""

560

Append data to buffer.

561

562

Args:

563

data (bytes): Data to append

564

"""

565

566

def unpack(self, fmt):

567

"""

568

Unpack data from buffer using struct format.

569

570

Args:

571

fmt (str): Struct format string

572

573

Returns:

574

tuple: Unpacked values

575

"""

576

577

def update(self, ptr, fmt, *args):

578

"""

579

Update buffer at specific position.

580

581

Args:

582

ptr (int): Buffer position

583

fmt (str): Struct format string

584

*args: Values to pack

585

"""

586

587

def hex(self):

588

"""

589

Return hex representation of buffer data.

590

591

Returns:

592

str: Hexadecimal string

593

"""

594

```

595

596

### DNS Buffer

597

598

Extended buffer with DNS name encoding/decoding and compression support.

599

600

```python { .api }

601

class DNSBuffer(Buffer):

602

"""

603

DNS-specific buffer with name compression and caching support.

604

605

Args:

606

data (bytes, optional): Initial buffer data

607

"""

608

def __init__(self, data=b""): ...

609

610

def decode_name(self, last=-1):

611

"""

612

Decode DNS name from buffer with compression support.

613

614

Args:

615

last (int, optional): Last position for compression

616

617

Returns:

618

DNSLabel: Decoded DNS name

619

"""

620

621

def encode_name(self, name):

622

"""

623

Encode DNS name to buffer with compression.

624

625

Args:

626

name (str or DNSLabel): DNS name to encode

627

"""

628

629

def encode_name_nocompress(self, name):

630

"""

631

Encode DNS name without compression.

632

633

Args:

634

name (str or DNSLabel): DNS name to encode

635

"""

636

```

637

638

### Bidirectional Mapping

639

640

Bidirectional mapping between numeric codes and text labels.

641

642

```python { .api }

643

class Bimap:

644

"""

645

Bidirectional mapping for DNS constants (e.g., QTYPE, CLASS, RCODE).

646

647

Args:

648

name (str): Mapping name for error messages

649

forward (dict): Forward mapping (code -> text)

650

error (Exception, optional): Exception class for errors

651

"""

652

def __init__(self, name, forward, error=AttributeError): ...

653

654

def get(self, key, default=None):

655

"""

656

Get value with default fallback.

657

658

Args:

659

key: Lookup key

660

default: Default value if key not found

661

662

Returns:

663

Value or default

664

"""

665

666

def __getitem__(self, key):

667

"""

668

Forward lookup: code -> text.

669

670

Args:

671

key: Numeric code

672

673

Returns:

674

str: Text label

675

"""

676

677

def __getattr__(self, key):

678

"""

679

Reverse lookup: text -> code.

680

681

Args:

682

key (str): Text label

683

684

Returns:

685

int: Numeric code

686

"""

687

```

688

689

### Zone File Parser

690

691

Parser for DNS zone file format with support for $TTL and $ORIGIN directives.

692

693

```python { .api }

694

class ZoneParser:

695

"""

696

Parser for DNS zone file format strings.

697

698

Args:

699

zone (str): Zone file format string

700

origin (str, optional): Default origin domain

701

ttl (int, optional): Default TTL value

702

"""

703

def __init__(self, zone, origin="", ttl=0): ...

704

705

def parse(self):

706

"""

707

Parse zone file and return resource records.

708

709

Returns:

710

list[RR]: List of parsed resource records

711

"""

712

713

def expect(self, token):

714

"""

715

Expect specific token in zone file.

716

717

Args:

718

token (str): Expected token

719

720

Raises:

721

Exception: If token not found

722

"""

723

724

def parse_label(self, label):

725

"""

726

Parse DNS label from zone file.

727

728

Args:

729

label (str): Label string

730

731

Returns:

732

DNSLabel: Parsed label

733

"""

734

735

def parse_rr(self, rr_line):

736

"""

737

Parse resource record line from zone file.

738

739

Args:

740

rr_line (str): Resource record line

741

742

Returns:

743

RR: Parsed resource record

744

"""

745

```

746

747

### Utility Functions

748

749

Core utility functions for DNS label and time handling.

750

751

```python { .api }

752

def label(label, origin=None):

753

"""

754

Create DNS label with optional origin.

755

756

Args:

757

label (str): Label string

758

origin (str or DNSLabel, optional): Origin domain

759

760

Returns:

761

DNSLabel: DNS label object

762

"""

763

764

def parse_time(s):

765

"""

766

Parse time value for DNS records.

767

768

Args:

769

s (str): Time string (e.g., "1h", "30m", "3600")

770

771

Returns:

772

int: Time value in seconds

773

"""

774

775

def decode_type_bitmap(type_bitmap):

776

"""

777

Decode NSEC type bitmap.

778

779

Args:

780

type_bitmap (bytes): Type bitmap data

781

782

Returns:

783

list[int]: List of record type numbers

784

"""

785

786

def encode_type_bitmap(rrlist):

787

"""

788

Encode NSEC type bitmap.

789

790

Args:

791

rrlist (list[int]): List of record type numbers

792

793

Returns:

794

bytes: Type bitmap data

795

"""

796

797

def unknown_qtype(name, key, forward):

798

"""

799

Handle unknown query types for dynamic mapping.

800

801

Args:

802

name (str): Mapping name

803

key: Lookup key

804

forward (bool): True for forward lookup

805

806

Returns:

807

Mapped value or TYPE### format

808

"""

809

```

810

811

## Usage Examples

812

813

### Basic Packet Parsing

814

815

```python

816

import binascii

817

from dnslib import *

818

819

# Parse DNS response packet

820

packet_hex = 'd5ad818000010005000000000377777706676f6f676c6503636f6d0000010001...'

821

packet = binascii.unhexlify(packet_hex.encode())

822

d = DNSRecord.parse(packet)

823

824

print(f"Header: {d.header}")

825

print(f"Question: {d.q}")

826

for rr in d.rr:

827

print(f"Answer: {rr}")

828

```

829

830

### Creating DNS Queries

831

832

```python

833

from dnslib import *

834

835

# Simple A query

836

q = DNSRecord.question("example.com")

837

print(q)

838

839

# MX query with specific header flags

840

q = DNSRecord.question("example.com", "MX")

841

q.header.rd = 1 # Recursion desired

842

print(q)

843

844

# DNSSEC query with EDNS0

845

q = DNSRecord.question("example.com", "A")

846

q.add_ar(EDNS0(flags="do", udp_len=4096))

847

q.header.ad = 1 # Authentic data

848

print(q)

849

```

850

851

### Creating DNS Responses

852

853

```python

854

from dnslib import *

855

856

# Create response manually

857

response = DNSRecord(

858

DNSHeader(qr=1, aa=1, ra=1),

859

q=DNSQuestion("example.com"),

860

a=RR("example.com", rdata=A("1.2.3.4"), ttl=300)

861

)

862

863

# Create response from query

864

q = DNSRecord.question("example.com")

865

a = q.reply()

866

a.add_answer(*RR.fromZone("example.com 300 IN A 1.2.3.4"))

867

a.add_answer(*RR.fromZone("example.com 300 IN AAAA 2001:db8::1"))

868

869

# Verify round-trip

870

packed = a.pack()

871

parsed = DNSRecord.parse(packed)

872

assert str(parsed) == str(a)

873

```

874

875

### Zone File Processing

876

877

```python

878

from dnslib import *

879

880

# Parse zone file format

881

zone_data = """

882

$TTL 300

883

$ORIGIN example.com.

884

885

@ IN MX 10 mail.example.com.

886

www IN A 1.2.3.4

887

IN TXT "Some Text"

888

mail IN CNAME www.example.com.

889

"""

890

891

# Create records from zone data

892

records = RR.fromZone(zone_data.strip())

893

for rr in records:

894

print(rr)

895

896

# Create response with zone data

897

q = DNSRecord.question("example.com", "ANY")

898

a = q.replyZone(zone_data.strip())

899

print(a)

900

```