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

0

# DNS Server Framework

1

2

Framework for creating custom DNS resolvers with UDP/TCP server support, request handling, and logging capabilities. The framework provides a simple interface for building DNS servers by subclassing BaseResolver and implementing custom resolution logic.

3

4

## Capabilities

5

6

### DNS Server

7

8

Main DNS server class providing UDP and TCP protocol support with threading and logging.

9

10

```python { .api }

11

class DNSServer:

12

"""

13

DNS server with UDP/TCP protocol support and request handling.

14

15

Args:

16

resolver (BaseResolver): Resolver instance for handling queries

17

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

18

address (str, optional): Server bind address (default: "")

19

logger (DNSLogger, optional): Logger instance

20

tcp (bool, optional): Enable TCP server (default: False)

21

ipv6 (bool, optional): Enable IPv6 support (default: False)

22

timeout (int, optional): Request timeout in seconds (default: 5)

23

handler (class, optional): Custom request handler class

24

"""

25

def __init__(self, resolver, port=53, address="", logger=None, **kwargs): ...

26

27

def start(self):

28

"""

29

Start DNS server and handle requests (blocking).

30

Server runs until interrupted.

31

"""

32

33

def start_thread(self):

34

"""

35

Start DNS server in background thread (non-blocking).

36

37

Returns:

38

threading.Thread: Server thread object

39

"""

40

41

def stop(self):

42

"""

43

Stop DNS server and cleanup resources.

44

"""

45

46

def isAlive(self):

47

"""

48

Check if server thread is running.

49

50

Returns:

51

bool: True if server is running

52

"""

53

```

54

55

### DNS Request Handler

56

57

Base request handler for processing DNS queries and generating responses.

58

59

```python { .api }

60

class DNSHandler:

61

"""

62

Base DNS request handler for UDP and TCP protocols.

63

Processes incoming DNS queries and generates responses.

64

"""

65

def handle(self):

66

"""

67

Handle incoming DNS request.

68

Parses request, calls resolver, and sends response.

69

"""

70

71

def get_reply(self, data):

72

"""

73

Process DNS query data and generate response.

74

75

Args:

76

data (bytes): Raw DNS query packet

77

78

Returns:

79

bytes: DNS response packet

80

"""

81

```

82

83

### Protocol Servers

84

85

Low-level UDP and TCP server implementations with threading support.

86

87

```python { .api }

88

class UDPServer:

89

"""

90

Threaded UDP server for DNS queries.

91

92

Args:

93

server_address (tuple): (address, port) tuple

94

handler (class): Request handler class

95

"""

96

def __init__(self, server_address, handler): ...

97

98

def serve_forever(self):

99

"""Start serving requests until interrupted."""

100

101

def shutdown(self):

102

"""Shutdown server and close socket."""

103

104

class TCPServer:

105

"""

106

Threaded TCP server for DNS queries.

107

108

Args:

109

server_address (tuple): (address, port) tuple

110

handler (class): Request handler class

111

"""

112

def __init__(self, server_address, handler): ...

113

114

def serve_forever(self):

115

"""Start serving requests until interrupted."""

116

117

def shutdown(self):

118

"""Shutdown server and close socket."""

119

```

120

121

### Base Resolver

122

123

Abstract base class for implementing custom DNS resolvers.

124

125

```python { .api }

126

class BaseResolver:

127

"""

128

Abstract base class for DNS resolvers.

129

Subclass this and implement resolve() method for custom logic.

130

"""

131

def resolve(self, request, handler):

132

"""

133

Resolve DNS query and return response.

134

Must be implemented by subclasses.

135

136

Args:

137

request (DNSRecord): Parsed DNS query

138

handler (DNSHandler): Request handler instance

139

140

Returns:

141

DNSRecord: DNS response record

142

"""

143

raise NotImplementedError

144

```

145

146

### DNS Logger

147

148

Configurable logging system for DNS server operations with request/response tracking.

149

150

```python { .api }

151

class DNSLogger:

152

"""

153

DNS server logger with configurable output and formatting.

154

155

Args:

156

log (str, optional): Comma-separated log types

157

("request", "reply", "truncated", "error", "recv", "send")

158

(default: "request,reply,truncated,error")

159

prefix (bool, optional): Include timestamp prefix (default: True)

160

logf (callable, optional): Custom log function (default: print)

161

"""

162

def __init__(self, log="request,reply,truncated,error", prefix=True, logf=None): ...

163

164

def log_recv(self, handler, data):

165

"""

166

Log received data.

167

168

Args:

169

handler (DNSHandler): Request handler

170

data (bytes): Received data

171

"""

172

173

def log_send(self, handler, data):

174

"""

175

Log sent data.

176

177

Args:

178

handler (DNSHandler): Request handler

179

data (bytes): Sent data

180

"""

181

182

def log_request(self, handler, request):

183

"""

184

Log DNS request.

185

186

Args:

187

handler (DNSHandler): Request handler

188

request (DNSRecord): DNS request

189

"""

190

191

def log_reply(self, handler, reply):

192

"""

193

Log DNS reply.

194

195

Args:

196

handler (DNSHandler): Request handler

197

reply (DNSRecord): DNS reply

198

"""

199

200

def log_truncated(self, handler, reply):

201

"""

202

Log truncated response.

203

204

Args:

205

handler (DNSHandler): Request handler

206

reply (DNSRecord): Truncated DNS reply

207

"""

208

209

def log_error(self, handler, e):

210

"""

211

Log error during request processing.

212

213

Args:

214

handler (DNSHandler): Request handler

215

e (Exception): Exception that occurred

216

"""

217

```

218

219

### UDP Server

220

221

UDP DNS server implementation with threading support.

222

223

```python { .api }

224

class UDPServer:

225

"""

226

UDP DNS server implementation.

227

Inherits from socketserver.ThreadingUDPServer.

228

229

Args:

230

server_address (tuple): (address, port) tuple

231

RequestHandlerClass (class): Request handler class

232

resolver (BaseResolver): DNS resolver instance

233

logger (DNSLogger, optional): Logger instance

234

timeout (int, optional): Request timeout

235

"""

236

def __init__(self, server_address, RequestHandlerClass, resolver, logger=None, timeout=5): ...

237

```

238

239

### TCP Server

240

241

TCP DNS server implementation with threading support.

242

243

```python { .api }

244

class TCPServer:

245

"""

246

TCP DNS server implementation.

247

Inherits from socketserver.ThreadingTCPServer.

248

249

Args:

250

server_address (tuple): (address, port) tuple

251

RequestHandlerClass (class): Request handler class

252

resolver (BaseResolver): DNS resolver instance

253

logger (DNSLogger, optional): Logger instance

254

timeout (int, optional): Request timeout

255

"""

256

def __init__(self, server_address, RequestHandlerClass, resolver, logger=None, timeout=5): ...

257

```

258

259

## Usage Examples

260

261

### Basic Custom Resolver

262

263

```python

264

from dnslib import *

265

from dnslib.server import DNSServer, BaseResolver

266

267

class SimpleResolver(BaseResolver):

268

"""Simple resolver that returns fixed IP for all A queries."""

269

270

def resolve(self, request, handler):

271

# Create reply based on request

272

reply = request.reply()

273

274

# Get the query

275

qname = request.q.qname

276

qtype = request.q.qtype

277

278

# Handle A record queries

279

if qtype == QTYPE.A:

280

# Add answer record

281

reply.add_answer(RR(qname, QTYPE.A, rdata=A("192.0.2.1"), ttl=300))

282

else:

283

# Set NXDOMAIN for other types

284

reply.header.rcode = RCODE.NXDOMAIN

285

286

return reply

287

288

# Create and start server

289

resolver = SimpleResolver()

290

server = DNSServer(resolver, port=5353, address="127.0.0.1")

291

print("Starting DNS server on 127.0.0.1:5353")

292

server.start()

293

```

294

295

### Advanced Custom Resolver with Logging

296

297

```python

298

from dnslib import *

299

from dnslib.server import DNSServer, BaseResolver, DNSLogger

300

import time

301

302

class TimestampResolver(BaseResolver):

303

"""Resolver that returns current timestamp in TXT records."""

304

305

def resolve(self, request, handler):

306

reply = request.reply()

307

qname = request.q.qname

308

qtype = request.q.qtype

309

310

if qtype == QTYPE.TXT:

311

# Return current timestamp

312

timestamp = str(int(time.time()))

313

reply.add_answer(RR(qname, QTYPE.TXT, rdata=TXT(f"timestamp={timestamp}"), ttl=1))

314

elif qtype == QTYPE.A:

315

# Return fixed IP

316

reply.add_answer(RR(qname, QTYPE.A, rdata=A("203.0.113.1"), ttl=300))

317

else:

318

reply.header.rcode = RCODE.NXDOMAIN

319

320

return reply

321

322

# Create logger with custom configuration

323

logger = DNSLogger(log="request,reply,error", prefix=True)

324

325

# Create resolver and server

326

resolver = TimestampResolver()

327

server = DNSServer(resolver, port=5353, address="127.0.0.1", logger=logger)

328

329

print("Starting DNS server with logging on 127.0.0.1:5353")

330

server.start()

331

```

332

333

### Multi-Protocol Server (UDP + TCP)

334

335

```python

336

from dnslib import *

337

from dnslib.server import DNSServer, BaseResolver

338

import threading

339

340

class EchoResolver(BaseResolver):

341

"""Resolver that echoes query information."""

342

343

def resolve(self, request, handler):

344

reply = request.reply()

345

qname = request.q.qname

346

qtype = request.q.qtype

347

348

# Create echo response in TXT record

349

echo_data = f"You queried {qname} for {QTYPE[qtype]}"

350

reply.add_answer(RR(qname, QTYPE.TXT, rdata=TXT(echo_data), ttl=60))

351

352

return reply

353

354

# Create resolver

355

resolver = EchoResolver()

356

357

# Start UDP server in thread

358

udp_server = DNSServer(resolver, port=5353, address="127.0.0.1", tcp=False)

359

udp_thread = udp_server.start_thread()

360

361

# Start TCP server in thread

362

tcp_server = DNSServer(resolver, port=5353, address="127.0.0.1", tcp=True)

363

tcp_thread = tcp_server.start_thread()

364

365

print("DNS servers running on UDP and TCP port 5353")

366

print("Press Ctrl+C to stop")

367

368

try:

369

# Keep main thread alive

370

while True:

371

time.sleep(1)

372

except KeyboardInterrupt:

373

print("Stopping servers...")

374

```

375

376

### Zone-Based Resolver

377

378

```python

379

from dnslib import *

380

from dnslib.server import DNSServer, BaseResolver

381

382

class ZoneResolver(BaseResolver):

383

"""Resolver that serves from zone data."""

384

385

def __init__(self, zone_data):

386

self.records = {}

387

# Parse zone data and index by name/type

388

for rr in RR.fromZone(zone_data):

389

key = (str(rr.rname), rr.rtype)

390

if key not in self.records:

391

self.records[key] = []

392

self.records[key].append(rr)

393

394

def resolve(self, request, handler):

395

reply = request.reply()

396

qname = str(request.q.qname)

397

qtype = request.q.qtype

398

399

# Look for exact match

400

key = (qname, qtype)

401

if key in self.records:

402

for rr in self.records[key]:

403

reply.add_answer(rr)

404

else:

405

# Check for ANY query

406

if qtype == QTYPE.ANY:

407

found = False

408

for (name, rtype), records in self.records.items():

409

if name == qname:

410

for rr in records:

411

reply.add_answer(rr)

412

found = True

413

if not found:

414

reply.header.rcode = RCODE.NXDOMAIN

415

else:

416

reply.header.rcode = RCODE.NXDOMAIN

417

418

return reply

419

420

# Zone data

421

zone_data = """

422

$TTL 300

423

example.com. IN A 192.0.2.1

424

example.com. IN MX 10 mail.example.com.

425

www.example.com. IN A 192.0.2.2

426

mail.example.com. IN A 192.0.2.3

427

ftp.example.com. IN CNAME www.example.com.

428

"""

429

430

# Create and start server

431

resolver = ZoneResolver(zone_data.strip())

432

server = DNSServer(resolver, port=5353, address="127.0.0.1")

433

434

print("Starting zone-based DNS server on 127.0.0.1:5353")

435

server.start()

436

```

437

438

### Server with Custom Request Handler

439

440

```python

441

from dnslib import *

442

from dnslib.server import DNSServer, BaseResolver, DNSHandler

443

import socketserver

444

445

class CustomDNSHandler(DNSHandler):

446

"""Custom handler with request filtering."""

447

448

def handle(self):

449

# Get client address

450

client_addr = self.client_address[0]

451

452

# Simple rate limiting example

453

if hasattr(self.server, 'client_counts'):

454

if client_addr not in self.server.client_counts:

455

self.server.client_counts[client_addr] = 0

456

self.server.client_counts[client_addr] += 1

457

458

# Reject if too many requests

459

if self.server.client_counts[client_addr] > 10:

460

print(f"Rate limiting client {client_addr}")

461

return

462

463

# Call parent handler

464

super().handle()

465

466

class RateLimitedResolver(BaseResolver):

467

"""Simple resolver with rate limiting."""

468

469

def resolve(self, request, handler):

470

reply = request.reply()

471

qname = request.q.qname

472

473

# Simple response

474

reply.add_answer(RR(qname, QTYPE.A, rdata=A("198.51.100.1"), ttl=300))

475

476

return reply

477

478

# Create server with custom handler

479

resolver = RateLimitedResolver()

480

server = DNSServer(resolver, port=5353, address="127.0.0.1", handler=CustomDNSHandler)

481

482

# Add client tracking

483

server.server.client_counts = {}

484

485

print("Starting rate-limited DNS server on 127.0.0.1:5353")

486

server.start()

487

```

488

489

### Server with Error Handling

490

491

```python

492

from dnslib import *

493

from dnslib.server import DNSServer, BaseResolver, DNSLogger

494

495

class RobustResolver(BaseResolver):

496

"""Resolver with comprehensive error handling."""

497

498

def resolve(self, request, handler):

499

try:

500

reply = request.reply()

501

qname = request.q.qname

502

qtype = request.q.qtype

503

504

# Validate query

505

if len(str(qname)) > 253: # Max domain length

506

reply.header.rcode = RCODE.FORMERR

507

return reply

508

509

# Handle different query types

510

if qtype == QTYPE.A:

511

reply.add_answer(RR(qname, QTYPE.A, rdata=A("203.0.113.10"), ttl=300))

512

elif qtype == QTYPE.AAAA:

513

reply.add_answer(RR(qname, QTYPE.AAAA, rdata=AAAA("2001:db8::10"), ttl=300))

514

elif qtype == QTYPE.TXT:

515

reply.add_answer(RR(qname, QTYPE.TXT, rdata=TXT("Hello from robust resolver"), ttl=60))

516

else:

517

reply.header.rcode = RCODE.NXDOMAIN

518

519

return reply

520

521

except Exception as e:

522

# Log error and return SERVFAIL

523

print(f"Error in resolver: {e}")

524

reply = request.reply()

525

reply.header.rcode = RCODE.SERVFAIL

526

return reply

527

528

# Create logger for debugging

529

logger = DNSLogger(log="request,reply,error,truncated", prefix=True)

530

531

# Create and start server

532

resolver = RobustResolver()

533

server = DNSServer(resolver, port=5353, address="127.0.0.1", logger=logger)

534

535

print("Starting robust DNS server with error handling on 127.0.0.1:5353")

536

server.start()

537

```