Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/scapy/layers/ntp.py: 94%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

314 statements  

1# SPDX-License-Identifier: GPL-2.0-only 

2# This file is part of Scapy 

3# See https://scapy.net/ for more information 

4# Copyright (C) Philippe Biondi <phil@secdev.org> 

5 

6""" 

7NTP (Network Time Protocol). 

8References : RFC 5905, RC 1305, ntpd source code 

9""" 

10 

11import struct 

12import time 

13import datetime 

14 

15from scapy.packet import Packet, bind_layers 

16from scapy.fields import ( 

17 BitEnumField, 

18 BitField, 

19 ByteEnumField, 

20 ByteField, 

21 ConditionalField, 

22 FieldLenField, 

23 FieldListField, 

24 FixedPointField, 

25 FlagsField, 

26 IP6Field, 

27 IPField, 

28 IntField, 

29 LEIntField, 

30 LEShortField, 

31 MayEnd, 

32 MultipleTypeField, 

33 PacketField, 

34 PacketListField, 

35 PadField, 

36 ShortField, 

37 SignedByteField, 

38 StrField, 

39 StrFixedLenEnumField, 

40 StrFixedLenField, 

41 StrLenField, 

42 XByteField, 

43 XStrField, 

44 XStrFixedLenField, 

45) 

46from scapy.layers.inet import UDP 

47from scapy.utils import lhex 

48from scapy.config import conf 

49 

50 

51############################################################################# 

52# Constants 

53############################################################################# 

54 

55_NTP_AUTH_MD5_MIN_SIZE = 68 

56_NTP_EXT_MIN_SIZE = 16 

57_NTP_HDR_WITH_EXT_MIN_SIZE = _NTP_AUTH_MD5_MIN_SIZE + _NTP_EXT_MIN_SIZE 

58_NTP_AUTH_MD5_TAIL_SIZE = 20 

59_NTP_AUTH_MD5_DGST_SIZE = 16 

60_NTP_PRIVATE_PACKET_MIN_SIZE = 8 

61 

62# ntpd "Private" messages are the shortest 

63_NTP_PACKET_MIN_SIZE = _NTP_PRIVATE_PACKET_MIN_SIZE 

64 

65_NTP_PRIVATE_REQ_PKT_TAIL_LEN = 28 

66 

67# seconds between 01-01-1900 and 01-01-1970 

68_NTP_BASETIME = 2208988800 

69 

70# include/ntp.h 

71_NTP_SHIFT = 8 

72_NTP_HASH_SIZE = 128 

73 

74 

75############################################################################# 

76# Fields and utilities 

77############################################################################# 

78 

79class XLEShortField(LEShortField): 

80 """ 

81 XShortField which value is encoded in little endian. 

82 """ 

83 

84 def i2repr(self, pkt, x): 

85 return lhex(self.i2h(pkt, x)) 

86 

87 

88class TimeStampField(FixedPointField): 

89 """ 

90 This field handles the timestamp fields in the NTP header. 

91 """ 

92 

93 def __init__(self, name, default): 

94 FixedPointField.__init__(self, name, default, 64, 32) 

95 

96 def i2repr(self, pkt, val): 

97 if val is None: 

98 return "--" 

99 val = self.i2h(pkt, val) 

100 if val < _NTP_BASETIME: 

101 return str(val) 

102 return time.strftime( 

103 "%a, %d %b %Y %H:%M:%S +0000", 

104 time.gmtime(int(val - _NTP_BASETIME)) 

105 ) 

106 

107 def any2i(self, pkt, val): 

108 if isinstance(val, str): 

109 val = int(time.mktime(time.strptime(val))) + _NTP_BASETIME 

110 elif isinstance(val, datetime.datetime): 

111 val = int(val.strftime("%s")) + _NTP_BASETIME 

112 return FixedPointField.any2i(self, pkt, val) 

113 

114 def i2m(self, pkt, val): 

115 if val is None: 

116 val = FixedPointField.any2i(self, pkt, time.time() + _NTP_BASETIME) 

117 return FixedPointField.i2m(self, pkt, val) 

118 

119 

120############################################################################# 

121# NTP 

122############################################################################# 

123 

124# RFC 5905 / Section 7.3 

125_leap_indicator = { 

126 0: "no warning", 

127 1: "last minute of the day has 61 seconds", 

128 2: "last minute of the day has 59 seconds", 

129 3: "unknown (clock unsynchronized)" 

130} 

131 

132 

133# RFC 5905 / Section 7.3 

134_ntp_modes = { 

135 0: "reserved", 

136 1: "symmetric active", 

137 2: "symmetric passive", 

138 3: "client", 

139 4: "server", 

140 5: "broadcast", 

141 6: "NTP control message", 

142 7: "reserved for private use" 

143} 

144 

145 

146# RFC 5905 / Section 7.3 

147_reference_identifiers = { 

148 b"GOES": "Geosynchronous Orbit Environment Satellite", 

149 b"GPS ": "Global Position System", 

150 b"GAL ": "Galileo Positioning System", 

151 b"PPS ": "Generic pulse-per-second", 

152 b"IRIG": "Inter-Range Instrumentation Group", 

153 b"WWVB": "LF Radio WWVB Ft. Collins, CO 60 kHz", 

154 b"DCF ": "LF Radio DCF77 Mainflingen, DE 77.5 kHz", 

155 b"HBG ": "LF Radio HBG Prangins, HB 75 kHz", 

156 b"MSF ": "LF Radio MSF Anthorn, UK 60 kHz", 

157 b"JJY ": "LF Radio JJY Fukushima, JP 40 kHz, Saga, JP 60 kHz", 

158 b"LORC": "MF Radio LORAN C station, 100 kHz", 

159 b"TDF ": "MF Radio Allouis, FR 162 kHz", 

160 b"CHU ": "HF Radio CHU Ottawa, Ontario", 

161 b"WWV ": "HF Radio WWV Ft. Collins, CO", 

162 b"WWVH": "HF Radio WWVH Kauai, HI", 

163 b"NIST": "NIST telephone modem", 

164 b"ACTS": "NIST telephone modem", 

165 b"USNO": "USNO telephone modem", 

166 b"PTB ": "European telephone modem", 

167} 

168 

169 

170# RFC 5905 / Section 7.4 

171_kiss_codes = { 

172 "ACST": "The association belongs to a unicast server.", 

173 "AUTH": "Server authentication failed.", 

174 "AUTO": "Autokey sequence failed.", 

175 "BCST": "The association belongs to a broadcast server.", 

176 "CRYP": "Cryptographic authentication or identification failed.", 

177 "DENY": "Access denied by remote server.", 

178 "DROP": "Lost peer in symmetric mode.", 

179 "RSTR": "Access denied due to local policy.", 

180 "INIT": "The association has not yet synchronized for the first time.", 

181 "MCST": "The association belongs to a dynamically discovered server.", 

182 "NKEY": "No key found.", 

183 "RATE": "Rate exceeded.", 

184 "RMOT": "Alteration of association from a remote host running ntpdc." 

185} 

186 

187 

188# Used by _ntp_dispatcher to instantiate the appropriate class 

189def _ntp_dispatcher(payload): 

190 """ 

191 Returns the right class for a given NTP packet. 

192 """ 

193 # By default, calling NTP() will build a NTP packet as defined in RFC 5905 

194 # (see the code of NTPHeader). Use NTPHeader for extension fields and MAC. 

195 if payload is None: 

196 return NTPHeader 

197 else: 

198 length = len(payload) 

199 if length >= _NTP_PACKET_MIN_SIZE: 

200 first_byte = payload[0] 

201 # Extract NTP mode 

202 mode = first_byte & 7 

203 return {6: NTPControl, 7: NTPPrivate}.get(mode, NTPHeader) 

204 return conf.raw_layer 

205 

206 

207class NTP(Packet): 

208 """ 

209 Base class that allows easier instantiation of a NTP packet from binary 

210 data. 

211 """ 

212 

213 @classmethod 

214 def dispatch_hook(cls, _pkt=None, *args, **kargs): 

215 """ 

216 Returns the right class for the given data. 

217 """ 

218 

219 return _ntp_dispatcher(_pkt) 

220 

221 def pre_dissect(self, s): 

222 """ 

223 Check that the payload is long enough to build a NTP packet. 

224 """ 

225 length = len(s) 

226 if length < _NTP_PACKET_MIN_SIZE: 

227 err = " ({}".format(length) + " is < _NTP_PACKET_MIN_SIZE " 

228 err += "({})).".format(_NTP_PACKET_MIN_SIZE) 

229 raise _NTPInvalidDataException(err) 

230 return s 

231 

232 def mysummary(self): 

233 return self.sprintf( 

234 "NTP v%ir,{0}.version%, %{0}.mode%".format(self.__class__.__name__) 

235 ) 

236 

237 

238class NTPAuthenticator(Packet): 

239 """ 

240 Packet handling the "authenticator" part of a NTP packet, as 

241 defined in RFC 5905. 

242 """ 

243 

244 name = "Authenticator" 

245 fields_desc = [ 

246 IntField("key_id", 0), 

247 XStrField("dgst", "") 

248 ] 

249 

250 def extract_padding(self, s): 

251 return b"", s 

252 

253 

254class NTPExtension(Packet): 

255 """ 

256 Packet handling a NTPv4 extension. 

257 """ 

258 

259 ######################################################################### 

260 # 

261 # RFC 7822 

262 ######################################################################### 

263 # 

264 # 7.5. NTP Extension Field Format 

265 # 

266 # In NTPv3, one or more extension fields can be inserted after the 

267 # header and before the MAC, if a MAC is present. 

268 # 

269 # Other than defining the field format, this document makes no use 

270 # of the field contents. An extension field contains a request or 

271 # response message in the format shown in Figure 14. 

272 # 

273 # 0 1 2 3 

274 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 

275 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

276 # | Field Type | Length | 

277 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

278 # . . 

279 # . Value . 

280 # . . 

281 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

282 # | Padding (as needed) | 

283 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

284 # 

285 # Figure 14: Extension Field Format 

286 # 

287 # 

288 # All extension fields are zero-padded to a word (four octets) 

289 # boundary. 

290 ######################################################################### 

291 # 

292 

293 name = "extension" 

294 fields_desc = [ 

295 ShortField("type", 0), 

296 ShortField("len", 0), 

297 PadField(PacketField("value", "", Packet), align=4, padwith=b"\x00") 

298 ] 

299 

300 

301class NTPExtPacketListField(PacketListField): 

302 

303 """ 

304 PacketListField handling NTPv4 extensions (NTPExtension list). 

305 """ 

306 

307 def m2i(self, pkt, m): 

308 ret = None 

309 if len(m) >= 16: 

310 ret = NTPExtension(m) 

311 else: 

312 ret = conf.raw_layer(m) 

313 return ret 

314 

315 def getfield(self, pkt, s): 

316 lst = [] 

317 remain = s 

318 length = len(s) 

319 if length > _NTP_AUTH_MD5_TAIL_SIZE: 

320 end = length - _NTP_AUTH_MD5_TAIL_SIZE 

321 extensions = s[:end] 

322 remain = s[end:] 

323 

324 extensions_len = len(extensions) 

325 while extensions_len >= 16: 

326 ext_len = struct.unpack("!H", extensions[2:4])[0] 

327 ext_len = min(ext_len, extensions_len) 

328 if ext_len < 1: 

329 ext_len = extensions_len 

330 current = extensions[:ext_len] 

331 extensions = extensions[ext_len:] 

332 current_packet = self.m2i(pkt, current) 

333 lst.append(current_packet) 

334 extensions_len = len(extensions) 

335 

336 if extensions_len > 0: 

337 lst.append(self.m2i(pkt, extensions)) 

338 

339 return remain, lst 

340 

341 

342class NTPExtensions(Packet): 

343 """ 

344 Packet handling the NTPv4 extensions and the "MAC part" of the packet. 

345 """ 

346 

347 ######################################################################### 

348 # 

349 # RFC 5905 / RFC 7822 

350 ######################################################################### 

351 # 

352 # 7.5. NTP Extension Field Format 

353 # 

354 # In NTPv4, one or more extension fields can be inserted after the 

355 # header and before the MAC, if a MAC is present. 

356 ######################################################################### 

357 # 

358 

359 name = "NTPv4 extensions" 

360 fields_desc = [ 

361 NTPExtPacketListField("extensions", [], Packet), 

362 PacketField("mac", NTPAuthenticator(), NTPAuthenticator) 

363 ] 

364 

365 

366class NTPHeader(NTP): 

367 

368 """ 

369 Packet handling the RFC 5905 NTP packet. 

370 """ 

371 

372 ######################################################################### 

373 # 

374 # RFC 5905 

375 ######################################################################### 

376 # 

377 # 0 1 2 3 

378 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 

379 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

380 # |LI | VN |Mode | Stratum | Poll | Precision | 

381 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

382 # | Root Delay | 

383 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

384 # | Root Dispersion | 

385 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

386 # | Reference ID | 

387 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

388 # | | 

389 # + Reference Timestamp (64) + 

390 # | | 

391 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

392 # | | 

393 # + Origin Timestamp (64) + 

394 # | | 

395 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

396 # | | 

397 # + Receive Timestamp (64) + 

398 # | | 

399 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

400 # | | 

401 # + Transmit Timestamp (64) + 

402 # | | 

403 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

404 # | | 

405 # . . 

406 # . Extension Field 1 (variable) . 

407 # . . 

408 # | | 

409 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

410 # | | 

411 # . . 

412 # . Extension Field 2 (variable) . 

413 # . . 

414 # | | 

415 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

416 # | Key Identifier | 

417 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

418 # | | 

419 # | dgst (128) | 

420 # | | 

421 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

422 # 

423 # Figure 8: Packet Header Format 

424 ######################################################################### 

425 # 

426 

427 name = "NTPHeader" 

428 match_subclass = True 

429 fields_desc = [ 

430 BitEnumField("leap", 0, 2, _leap_indicator), 

431 BitField("version", 4, 3), 

432 BitEnumField("mode", 3, 3, _ntp_modes), 

433 BitField("stratum", 2, 8), 

434 SignedByteField("poll", 0xa), 

435 SignedByteField("precision", 0), 

436 FixedPointField("delay", 0, size=32, frac_bits=16), 

437 FixedPointField("dispersion", 0, size=32, frac_bits=16), 

438 ConditionalField(IPField("id", "127.0.0.1"), lambda p: p.stratum > 1), 

439 ConditionalField( 

440 StrFixedLenEnumField( 

441 "ref_id", 

442 "", 

443 length=4, 

444 enum=_reference_identifiers 

445 ), 

446 lambda p: p.stratum < 2 

447 ), 

448 TimeStampField("ref", 0), 

449 TimeStampField("orig", None), 

450 TimeStampField("recv", 0), 

451 TimeStampField("sent", None), 

452 ] 

453 

454 def guess_payload_class(self, payload): 

455 """ 

456 Handles NTPv4 extensions and MAC part (when authentication is used.) 

457 """ 

458 plen = len(payload) 

459 

460 # length of MD5, SHA1, SHA256, SHA384, SHA512 

461 if plen - 4 in [16, 20, 32, 48, 64]: 

462 return NTPAuthenticator 

463 elif plen > _NTP_AUTH_MD5_TAIL_SIZE: 

464 return NTPExtensions 

465 

466 return Packet.guess_payload_class(self, payload) 

467 

468 

469class _NTPInvalidDataException(Exception): 

470 """ 

471 Raised when it is not possible to instantiate a NTP packet with the 

472 given data. 

473 """ 

474 

475 def __init__(self, details): 

476 Exception.__init__( 

477 self, 

478 "Data does not seem to be a valid NTP message" + details 

479 ) 

480 

481 

482############################################################################## 

483# Private (mode 7) 

484############################################################################## 

485 

486# Operation codes 

487_op_codes = { 

488 0: "CTL_OP_UNSPEC", 

489 1: "CTL_OP_READSTAT", 

490 2: "CTL_OP_READVAR", 

491 3: "CTL_OP_WRITEVAR", 

492 4: "CTL_OP_READCLOCK", 

493 5: "CTL_OP_WRITECLOCK", 

494 6: "CTL_OP_SETTRAP", 

495 7: "CTL_OP_ASYNCMSG", 

496 8: "CTL_OP_CONFIGURE", 

497 9: "CTL_OP_SAVECONFIG", 

498 10: "CTL_OP_READ_MRU", 

499 11: "CTL_OP_READ_ORDLIST_A", 

500 12: "CTL_OP_REQ_NONCE", 

501 31: "CTL_OP_UNSETTRAP" 

502} 

503 

504 

505# System status words 

506_system_statuses = { 

507 0: "no warning", 

508 1: "last minute was 61 seconds", 

509 2: "last minute was 59 seconds", 

510 3: "alarm condition (clock not synchronized)" 

511} 

512 

513 

514_clock_sources = { 

515 0: "unspecified or unknown", 

516 1: " Calibrated atomic clock", 

517 2: "VLF (band 4) or LF (band 5) radio", 

518 3: "HF (band 7) radio", 

519 4: "UHF (band 9) satellite", 

520 5: "local net", 

521 6: "UDP/NTP", 

522 7: "UDP/TIME", 

523 8: "eyeball-and-wristwatch", 

524 9: "telephone modem" 

525} 

526 

527 

528_system_event_codes = { 

529 0: "unspecified", 

530 1: "system restart", 

531 2: "system or hardware fault", 

532 3: "system new status word (leap bits or synchronization change)", 

533 4: "system new synchronization source or stratum (sys.peer or sys.stratum change)", # noqa: E501 

534 5: "system clock reset (offset correction exceeds CLOCK.MAX)", 

535 6: "system invalid time or date", 

536 7: "system clock exception", 

537} 

538 

539 

540# Peer status words 

541_peer_statuses = { 

542 0: "configured", 

543 1: "authentication enabled", 

544 2: "authentication okay", 

545 3: "reachability okay", 

546 4: "reserved" 

547} 

548 

549 

550_peer_selection = { 

551 0: "rejected", 

552 1: "passed sanity checks", 

553 2: "passed correctness checks", 

554 3: "passed candidate checks", 

555 4: "passed outlyer checks", 

556 5: "current synchronization source; max distance exceeded", 

557 6: "current synchronization source; max distance okay", 

558 7: "reserved" 

559} 

560 

561 

562_peer_event_codes = { 

563 0: "unspecified", 

564 1: "peer IP error", 

565 2: "peer authentication failure", 

566 3: "peer unreachable", 

567 4: "peer reachable", 

568 5: "peer clock exception", 

569} 

570 

571 

572# Clock status words 

573_clock_statuses = { 

574 0: "clock operating within nominals", 

575 1: "reply timeout", 

576 2: "bad reply format", 

577 3: "hardware or software fault", 

578 4: "propagation failure", 

579 5: "bad date format or value", 

580 6: "bad time format or value" 

581} 

582 

583 

584# Error status words 

585_error_statuses = { 

586 0: "unspecified", 

587 1: "authentication failure", 

588 2: "invalid message length or format", 

589 3: "invalid opcode", 

590 4: "unknown association identifier", 

591 5: "unknown variable name", 

592 6: "invalid variable value", 

593 7: "administratively prohibited" 

594} 

595 

596 

597class NTPSystemStatusPacket(Packet): 

598 

599 """ 

600 Packet handling the system status fields. 

601 """ 

602 

603 name = "system status" 

604 fields_desc = [ 

605 BitEnumField("leap_indicator", 0, 2, _system_statuses), 

606 BitEnumField("clock_source", 0, 6, _clock_sources), 

607 BitField("system_event_counter", 0, 4), 

608 BitEnumField("system_event_code", 0, 4, _system_event_codes), 

609 ] 

610 

611 def extract_padding(self, s): 

612 return b"", s 

613 

614 

615class NTPPeerStatusPacket(Packet): 

616 """ 

617 Packet handling the peer status fields. 

618 """ 

619 

620 name = "peer status" 

621 fields_desc = [ 

622 BitField("configured", 0, 1), 

623 BitField("auth_enabled", 0, 1), 

624 BitField("authentic", 0, 1), 

625 BitField("reachability", 0, 1), 

626 BitField("reserved", 0, 1), 

627 BitEnumField("peer_sel", 0, 3, _peer_selection), 

628 BitField("peer_event_counter", 0, 4), 

629 BitEnumField("peer_event_code", 0, 4, _peer_event_codes), 

630 ] 

631 

632 def extract_padding(self, s): 

633 return b"", s 

634 

635 

636class NTPClockStatusPacket(Packet): 

637 """ 

638 Packet handling the clock status fields. 

639 """ 

640 

641 name = "clock status" 

642 fields_desc = [ 

643 BitEnumField("clock_status", 0, 8, _clock_statuses), 

644 BitField("code", 0, 8) 

645 ] 

646 

647 def extract_padding(self, s): 

648 return b"", s 

649 

650 

651class NTPErrorStatusPacket(Packet): 

652 """ 

653 Packet handling the error status fields. 

654 """ 

655 

656 name = "error status" 

657 fields_desc = [ 

658 BitEnumField("error_code", 0, 8, _error_statuses), 

659 BitField("reserved", 0, 8) 

660 ] 

661 

662 def extract_padding(self, s): 

663 return b"", s 

664 

665 

666class NTPPeerStatusDataPacket(Packet): 

667 """ 

668 Packet handling the data field when op_code is CTL_OP_READSTAT 

669 and the association_id field is null. 

670 """ 

671 

672 name = "data / peer status" 

673 fields_desc = [ 

674 ShortField("association_id", 0), 

675 PacketField("peer_status", NTPPeerStatusPacket(), NTPPeerStatusPacket), 

676 ] 

677 

678 def extract_padding(self, s): 

679 return b"", s 

680 

681 

682class NTPControlStatusField(PacketField): 

683 """ 

684 The various types of the "status" field. 

685 """ 

686 # RFC 9327 sect 3 

687 def m2i(self, pkt, m): 

688 association_id = struct.unpack("!H", m[2:4])[0] 

689 

690 if pkt.err == 1: 

691 return NTPErrorStatusPacket(m) 

692 elif pkt.op_code in [4, 5]: # Read/write clock 

693 return NTPClockStatusPacket(m) 

694 else: 

695 if association_id != 0: 

696 return NTPPeerStatusPacket(m) 

697 else: 

698 return NTPSystemStatusPacket(m) 

699 

700 

701class NTPControl(NTP): 

702 """ 

703 Packet handling NTP mode 6 / "Control" messages. 

704 """ 

705 deprecated_fields = { 

706 "status_word": ("status", "2.6.2"), 

707 } 

708 # RFC 9327 sect 2 

709 name = "NTP Control message" 

710 match_subclass = True 

711 fields_desc = [ 

712 BitEnumField("leap", 0, 2, _leap_indicator), 

713 BitField("version", 2, 3), 

714 BitEnumField("mode", 6, 3, _ntp_modes), 

715 BitField("response", 0, 1), 

716 BitField("err", 0, 1), 

717 BitField("more", 0, 1), 

718 BitEnumField("op_code", 0, 5, _op_codes), 

719 ShortField("sequence", 0), 

720 MultipleTypeField( 

721 [ 

722 ( 

723 ShortField("status", 0), 

724 lambda pkt: pkt.response == 0 or pkt.op_code in [6, 7] 

725 ) 

726 ], 

727 NTPControlStatusField("status", NTPSystemStatusPacket(), None), 

728 ), 

729 ShortField("association_id", 0), 

730 ShortField("offset", 0), 

731 FieldLenField("count", None, length_of="data"), 

732 MayEnd( 

733 PadField( 

734 MultipleTypeField( 

735 # RFC 1305 

736 [ 

737 ( 

738 PacketListField( 

739 "data", 

740 "", 

741 NTPPeerStatusDataPacket, 

742 length_from=lambda p: p.count, 

743 ), 

744 lambda pkt: ( 

745 pkt.response and 

746 pkt.op_code == 1 and 

747 pkt.association_id == 0 

748 ) 

749 ), 

750 ], 

751 StrLenField("data", "", length_from=lambda pkt: pkt.count), 

752 ), 

753 align=4 

754 ) 

755 ), 

756 PacketField("authenticator", "", NTPAuthenticator), 

757 ] 

758 

759 

760############################################################################## 

761# Private (mode 7) 

762############################################################################## 

763 

764_information_error_codes = { 

765 0: "INFO_OKAY", 

766 1: "INFO_ERR_IMPL", 

767 2: "INFO_ERR_REQ", 

768 3: "INFO_ERR_FMT", 

769 4: "INFO_ERR_NODATA", 

770 7: "INFO_ERR_AUTH" 

771} 

772 

773 

774_implementations = { 

775 0: "IMPL_UNIV", 

776 2: "IMPL_XNTPD_OLD", 

777 3: "XNTPD" 

778} 

779 

780 

781_request_codes = { 

782 0: "REQ_PEER_LIST", 

783 1: "REQ_PEER_LIST_SUM", 

784 2: "REQ_PEER_INFO", 

785 3: "REQ_PEER_STATS", 

786 4: "REQ_SYS_INFO", 

787 5: "REQ_SYS_STATS", 

788 6: "REQ_IO_STATS", 

789 7: "REQ_MEM_STATS", 

790 8: "REQ_LOOP_INFO", 

791 9: "REQ_TIMER_STATS", 

792 10: "REQ_CONFIG", 

793 11: "REQ_UNCONFIG", 

794 12: "REQ_SET_SYS_FLAG", 

795 13: "REQ_CLR_SYS_FLAG", 

796 14: "REQ_MONITOR", 

797 15: "REQ_NOMONITOR", 

798 16: "REQ_GET_RESTRICT", 

799 17: "REQ_RESADDFLAGS", 

800 18: "REQ_RESSUBFLAGS", 

801 19: "REQ_UNRESTRICT", 

802 20: "REQ_MON_GETLIST", 

803 21: "REQ_RESET_STATS", 

804 22: "REQ_RESET_PEER", 

805 23: "REQ_REREAD_KEYS", 

806 24: "REQ_DO_DIRTY_HACK", 

807 25: "REQ_DONT_DIRTY_HACK", 

808 26: "REQ_TRUSTKEY", 

809 27: "REQ_UNTRUSTKEY", 

810 28: "REQ_AUTHINFO", 

811 29: "REQ_TRAPS", 

812 30: "REQ_ADD_TRAP", 

813 31: "REQ_CLR_TRAP", 

814 32: "REQ_REQUEST_KEY", 

815 33: "REQ_CONTROL_KEY", 

816 34: "REQ_GET_CTLSTATS", 

817 35: "REQ_GET_LEAPINFO", 

818 36: "REQ_GET_CLOCKINFO", 

819 37: "REQ_SET_CLKFUDGE", 

820 38: "REQ_GET_KERNEL", 

821 39: "REQ_GET_CLKBUGINFO", 

822 41: "REQ_SET_PRECISION", 

823 42: "REQ_MON_GETLIST_1", 

824 43: "REQ_HOSTNAME_ASSOCID", 

825 44: "REQ_IF_STATS", 

826 45: "REQ_IF_RELOAD" 

827} 

828 

829 

830# Flags in the peer information returns 

831_peer_flags = [ 

832 "INFO_FLAG_CONFIG", 

833 "INFO_FLAG_SYSPEER", 

834 "INFO_FLAG_BURST", 

835 "INFO_FLAG_REFCLOCK", 

836 "INFO_FLAG_PREFER", 

837 "INFO_FLAG_AUTHENABLE", 

838 "INFO_FLAG_SEL_CANDIDATE", 

839 "INFO_FLAG_SHORTLIST", 

840 "INFO_FLAG_IBURST" 

841] 

842 

843 

844# Flags in the system information returns 

845_sys_info_flags = [ 

846 "INFO_FLAG_BCLIENT", 

847 "INFO_FLAG_AUTHENTICATE", 

848 "INFO_FLAG_NTP", 

849 "INFO_FLAG_KERNEL", 

850 "INFO_FLAG_CAL", 

851 "INFO_FLAG_PPS_SYNC", 

852 "INFO_FLAG_MONITOR", 

853 "INFO_FLAG_FILEGEN", 

854] 

855 

856 

857class NTPInfoPeerList(Packet): 

858 

859 """ 

860 Used to return raw lists of peers. 

861 """ 

862 name = "info_peer_list" 

863 fields_desc = [ 

864 IPField("addr", "0.0.0.0"), 

865 ShortField("port", 0), 

866 ByteEnumField("hmode", 0, _ntp_modes), 

867 FlagsField("flags", 0, 8, _peer_flags), 

868 IntField("v6_flag", 0), 

869 IntField("unused1", 0), 

870 IP6Field("addr6", "::") 

871 ] 

872 

873 

874class NTPInfoPeerSummary(Packet): 

875 """ 

876 Sort of the info that ntpdc returns by default. 

877 """ 

878 name = "info_peer_summary" 

879 fields_desc = [ 

880 IPField("dstaddr", "0.0.0.0"), 

881 IPField("srcaddr", "0.0.0.0"), 

882 ShortField("srcport", 0), 

883 ByteField("stratum", 0), 

884 ByteField("hpoll", 0), 

885 ByteField("ppoll", 0), 

886 ByteField("reach", 0), 

887 FlagsField("flags", 0, 8, _peer_flags), 

888 ByteField("hmode", _ntp_modes), 

889 FixedPointField("delay", 0, size=32, frac_bits=16), 

890 TimeStampField("offset", 0), 

891 FixedPointField("dispersion", 0, size=32, frac_bits=16), 

892 IntField("v6_flag", 0), 

893 IntField("unused1", 0), 

894 IP6Field("dstaddr6", "::"), 

895 IP6Field("srcaddr6", "::") 

896 ] 

897 

898 

899class NTPInfoPeer(Packet): 

900 """ 

901 Peer information structure. 

902 """ 

903 

904 name = "info_peer" 

905 fields_desc = [ 

906 IPField("dstaddr", "0.0.0.0"), 

907 IPField("srcaddr", "0.0.0.0"), 

908 ShortField("srcport", 0), 

909 FlagsField("flags", 0, 8, _peer_flags), 

910 ByteField("leap", 0), 

911 ByteEnumField("hmode", 0, _ntp_modes), 

912 ByteField("pmode", 0), 

913 ByteField("stratum", 0), 

914 ByteField("ppoll", 0), 

915 ByteField("hpoll", 0), 

916 SignedByteField("precision", 0), 

917 ByteField("version", 0), 

918 ByteField("unused8", 0), 

919 ByteField("reach", 0), 

920 ByteField("unreach", 0), 

921 XByteField("flash", 0), 

922 ByteField("ttl", 0), 

923 XLEShortField("flash2", 0), 

924 ShortField("associd", 0), 

925 LEIntField("keyid", 0), 

926 IntField("pkeyid", 0), 

927 IPField("refid", 0), 

928 IntField("timer", 0), 

929 FixedPointField("rootdelay", 0, size=32, frac_bits=16), 

930 FixedPointField("rootdispersion", 0, size=32, frac_bits=16), 

931 TimeStampField("reftime", 0), 

932 TimeStampField("org", 0), 

933 TimeStampField("rec", 0), 

934 TimeStampField("xmt", 0), 

935 FieldListField( 

936 "filtdelay", 

937 [0.0 for i in range(0, _NTP_SHIFT)], 

938 FixedPointField("", 0, size=32, frac_bits=16), 

939 count_from=lambda p: _NTP_SHIFT 

940 ), 

941 FieldListField( 

942 "filtoffset", 

943 [0.0 for i in range(0, _NTP_SHIFT)], 

944 TimeStampField("", 0), 

945 count_from=lambda p: _NTP_SHIFT 

946 ), 

947 FieldListField( 

948 "order", 

949 [0 for i in range(0, _NTP_SHIFT)], 

950 ByteField("", 0), 

951 count_from=lambda p: _NTP_SHIFT 

952 ), 

953 FixedPointField("delay", 0, size=32, frac_bits=16), 

954 FixedPointField("dispersion", 0, size=32, frac_bits=16), 

955 TimeStampField("offset", 0), 

956 FixedPointField("selectdisp", 0, size=32, frac_bits=16), 

957 IntField("unused1", 0), 

958 IntField("unused2", 0), 

959 IntField("unused3", 0), 

960 IntField("unused4", 0), 

961 IntField("unused5", 0), 

962 IntField("unused6", 0), 

963 IntField("unused7", 0), 

964 FixedPointField("estbdelay", 0, size=32, frac_bits=16), 

965 IntField("v6_flag", 0), 

966 IntField("unused9", 0), 

967 IP6Field("dstaddr6", "::"), 

968 IP6Field("srcaddr6", "::"), 

969 ] 

970 

971 

972class NTPInfoPeerStats(Packet): 

973 """ 

974 Peer statistics structure. 

975 """ 

976 

977 name = "info_peer_stats" 

978 fields_desc = [ 

979 IPField("dstaddr", "0.0.0.0"), 

980 IPField("srcaddr", "0.0.0.0"), 

981 ShortField("srcport", 0), 

982 FlagsField("flags", 0, 16, _peer_flags), 

983 IntField("timereset", 0), 

984 IntField("timereceived", 0), 

985 IntField("timetosend", 0), 

986 IntField("timereachable", 0), 

987 IntField("sent", 0), 

988 IntField("unused1", 0), 

989 IntField("processed", 0), 

990 IntField("unused2", 0), 

991 IntField("badauth", 0), 

992 IntField("bogusorg", 0), 

993 IntField("oldpkt", 0), 

994 IntField("unused3", 0), 

995 IntField("unused4", 0), 

996 IntField("seldisp", 0), 

997 IntField("selbroken", 0), 

998 IntField("unused5", 0), 

999 ByteField("candidate", 0), 

1000 ByteField("unused6", 0), 

1001 ByteField("unused7", 0), 

1002 ByteField("unused8", 0), 

1003 IntField("v6_flag", 0), 

1004 IntField("unused9", 0), 

1005 IP6Field("dstaddr6", "::"), 

1006 IP6Field("srcaddr6", "::"), 

1007 ] 

1008 

1009 

1010class NTPInfoLoop(Packet): 

1011 """ 

1012 Loop filter variables. 

1013 """ 

1014 

1015 name = "info_loop" 

1016 fields_desc = [ 

1017 TimeStampField("last_offset", 0), 

1018 TimeStampField("drift_comp", 0), 

1019 IntField("compliance", 0), 

1020 IntField("watchdog_timer", 0) 

1021 ] 

1022 

1023 

1024class NTPInfoSys(Packet): 

1025 """ 

1026 System info. Mostly the sys.* variables, plus a few unique to 

1027 the implementation. 

1028 """ 

1029 

1030 name = "info_sys" 

1031 fields_desc = [ 

1032 IPField("peer", "0.0.0.0"), 

1033 ByteField("peer_mode", 0), 

1034 ByteField("leap", 0), 

1035 ByteField("stratum", 0), 

1036 SignedByteField("precision", 0), 

1037 FixedPointField("rootdelay", 0, size=32, frac_bits=16), 

1038 FixedPointField("rootdispersion", 0, size=32, frac_bits=16), 

1039 IPField("refid", 0), 

1040 TimeStampField("reftime", 0), 

1041 IntField("poll", 0), 

1042 FlagsField("flags", 0, 8, _sys_info_flags), 

1043 ByteField("unused1", 0), 

1044 ByteField("unused2", 0), 

1045 ByteField("unused3", 0), 

1046 FixedPointField("bdelay", 0, size=32, frac_bits=16), 

1047 FixedPointField("frequency", 0, size=32, frac_bits=16), 

1048 TimeStampField("authdelay", 0), 

1049 FixedPointField("stability", 0, size=32, frac_bits=16), 

1050 IntField("v6_flag", 0), 

1051 IntField("unused4", 0), 

1052 IP6Field("peer6", "::") 

1053 ] 

1054 

1055 

1056class NTPInfoSysStats(Packet): 

1057 """ 

1058 System stats. These are collected in the protocol module. 

1059 """ 

1060 

1061 name = "info_sys_stats" 

1062 fields_desc = [ 

1063 IntField("timeup", 0), 

1064 IntField("timereset", 0), 

1065 IntField("denied", 0), 

1066 IntField("oldversionpkt", 0), 

1067 IntField("newversionpkt", 0), 

1068 IntField("unknownversion", 0), 

1069 IntField("badlength", 0), 

1070 IntField("processed", 0), 

1071 IntField("badauth", 0), 

1072 IntField("received", 0), 

1073 IntField("limitrejected", 0) 

1074 ] 

1075 

1076 

1077class NTPInfoMemStats(Packet): 

1078 """ 

1079 Peer memory statistics. 

1080 """ 

1081 

1082 name = "info_mem_stats" 

1083 fields_desc = [ 

1084 IntField("timereset", 0), 

1085 ShortField("totalpeermem", 0), 

1086 ShortField("freepeermem", 0), 

1087 IntField("findpeer_calls", 0), 

1088 IntField("allocations", 0), 

1089 IntField("demobilizations", 0), 

1090 FieldListField( 

1091 "hashcount", 

1092 [0.0 for i in range(0, _NTP_HASH_SIZE)], 

1093 ByteField("", 0), 

1094 count_from=lambda p: _NTP_HASH_SIZE, 

1095 max_count=_NTP_HASH_SIZE 

1096 ) 

1097 ] 

1098 

1099 

1100class NTPInfoIOStats(Packet): 

1101 """ 

1102 I/O statistics. 

1103 """ 

1104 

1105 name = "info_io_stats" 

1106 fields_desc = [ 

1107 IntField("timereset", 0), 

1108 ShortField("totalrecvbufs", 0), 

1109 ShortField("freerecvbufs", 0), 

1110 ShortField("fullrecvbufs", 0), 

1111 ShortField("lowwater", 0), 

1112 IntField("dropped", 0), 

1113 IntField("ignored", 0), 

1114 IntField("received", 0), 

1115 IntField("sent", 0), 

1116 IntField("notsent", 0), 

1117 IntField("interrupts", 0), 

1118 IntField("int_received", 0) 

1119 ] 

1120 

1121 

1122class NTPInfoTimerStats(Packet): 

1123 """ 

1124 Timer stats. 

1125 """ 

1126 

1127 name = "info_timer_stats" 

1128 fields_desc = [ 

1129 IntField("timereset", 0), 

1130 IntField("alarms", 0), 

1131 IntField("overflows", 0), 

1132 IntField("xmtcalls", 0), 

1133 ] 

1134 

1135 

1136_conf_peer_flags = [ 

1137 "CONF_FLAG_AUTHENABLE", 

1138 "CONF_FLAG_PREFER", 

1139 "CONF_FLAG_BURST", 

1140 "CONF_FLAG_IBURST", 

1141 "CONF_FLAG_NOSELECT", 

1142 "CONF_FLAG_SKEY" 

1143] 

1144 

1145 

1146class NTPConfPeer(Packet): 

1147 """ 

1148 Structure for passing peer configuration information. 

1149 """ 

1150 

1151 name = "conf_peer" 

1152 fields_desc = [ 

1153 IPField("peeraddr", "0.0.0.0"), 

1154 ByteField("hmode", 0), 

1155 ByteField("version", 0), 

1156 ByteField("minpoll", 0), 

1157 ByteField("maxpoll", 0), 

1158 FlagsField("flags", 0, 8, _conf_peer_flags), 

1159 ByteField("ttl", 0), 

1160 ShortField("unused1", 0), 

1161 IntField("keyid", 0), 

1162 StrFixedLenField("keystr", "", length=128), 

1163 IntField("v6_flag", 0), 

1164 IntField("unused2", 0), 

1165 IP6Field("peeraddr6", "::") 

1166 ] 

1167 

1168 

1169class NTPConfUnpeer(Packet): 

1170 """ 

1171 Structure for passing peer deletion information. 

1172 """ 

1173 

1174 name = "conf_unpeer" 

1175 fields_desc = [ 

1176 IPField("peeraddr", "0.0.0.0"), 

1177 IntField("v6_flag", 0), 

1178 IP6Field("peeraddr6", "::") 

1179 ] 

1180 

1181 

1182_restrict_flags = [ 

1183 "RES_IGNORE", 

1184 "RES_DONTSERVE", 

1185 "RES_DONTTRUST", 

1186 "RES_VERSION", 

1187 "RES_NOPEER", 

1188 "RES_LIMITED", 

1189 "RES_NOQUERY", 

1190 "RES_NOMODIFY", 

1191 "RES_NOTRAP", 

1192 "RES_LPTRAP", 

1193 "RES_KOD", 

1194 "RES_MSSNTP", 

1195 "RES_FLAKE", 

1196 "RES_NOMRULIST", 

1197] 

1198 

1199 

1200class NTPConfRestrict(Packet): 

1201 """ 

1202 Structure used for specifying restrict entries. 

1203 """ 

1204 

1205 name = "conf_restrict" 

1206 fields_desc = [ 

1207 IPField("addr", "0.0.0.0"), 

1208 IPField("mask", "0.0.0.0"), 

1209 FlagsField("flags", 0, 16, _restrict_flags), 

1210 ShortField("m_flags", 0), 

1211 IntField("v6_flag", 0), 

1212 IP6Field("addr6", "::"), 

1213 IP6Field("mask6", "::") 

1214 ] 

1215 

1216 

1217class NTPInfoKernel(Packet): 

1218 """ 

1219 Structure used for returning kernel pll/PPS information 

1220 """ 

1221 

1222 name = "info_kernel" 

1223 fields_desc = [ 

1224 IntField("offset", 0), 

1225 IntField("freq", 0), 

1226 IntField("maxerror", 0), 

1227 IntField("esterror", 0), 

1228 ShortField("status", 0), 

1229 ShortField("shift", 0), 

1230 IntField("constant", 0), 

1231 IntField("precision", 0), 

1232 IntField("tolerance", 0), 

1233 IntField("ppsfreq", 0), 

1234 IntField("jitter", 0), 

1235 IntField("stabil", 0), 

1236 IntField("jitcnt", 0), 

1237 IntField("calcnt", 0), 

1238 IntField("errcnt", 0), 

1239 IntField("stbcnt", 0), 

1240 ] 

1241 

1242 

1243class NTPInfoIfStatsIPv4(Packet): 

1244 """ 

1245 Interface statistics. 

1246 """ 

1247 

1248 name = "info_if_stats" 

1249 fields_desc = [ 

1250 PadField(IPField("unaddr", "0.0.0.0"), 16, padwith=b"\x00"), 

1251 PadField(IPField("unbcast", "0.0.0.0"), 16, padwith=b"\x00"), 

1252 PadField(IPField("unmask", "0.0.0.0"), 16, padwith=b"\x00"), 

1253 IntField("v6_flag", 0), 

1254 StrFixedLenField("ifname", "", length=32), 

1255 IntField("flags", 0), 

1256 IntField("last_ttl", 0), 

1257 IntField("num_mcast", 0), 

1258 IntField("received", 0), 

1259 IntField("sent", 0), 

1260 IntField("notsent", 0), 

1261 IntField("uptime", 0), 

1262 IntField("scopeid", 0), 

1263 IntField("ifindex", 0), 

1264 IntField("ifnum", 0), 

1265 IntField("peercnt", 0), 

1266 ShortField("family", 0), 

1267 ByteField("ignore_packets", 0), 

1268 ByteField("action", 0), 

1269 IntField("_filler0", 0) 

1270 ] 

1271 

1272 

1273class NTPInfoIfStatsIPv6(Packet): 

1274 """ 

1275 Interface statistics. 

1276 """ 

1277 

1278 name = "info_if_stats" 

1279 fields_desc = [ 

1280 IP6Field("unaddr", "::"), 

1281 IP6Field("unbcast", "::"), 

1282 IP6Field("unmask", "::"), 

1283 IntField("v6_flag", 0), 

1284 StrFixedLenField("ifname", "", length=32), 

1285 IntField("flags", 0), 

1286 IntField("last_ttl", 0), 

1287 IntField("num_mcast", 0), 

1288 IntField("received", 0), 

1289 IntField("sent", 0), 

1290 IntField("notsent", 0), 

1291 IntField("uptime", 0), 

1292 IntField("scopeid", 0), 

1293 IntField("ifindex", 0), 

1294 IntField("ifnum", 0), 

1295 IntField("peercnt", 0), 

1296 ShortField("family", 0), 

1297 ByteField("ignore_packets", 0), 

1298 ByteField("action", 0), 

1299 IntField("_filler0", 0) 

1300 ] 

1301 

1302 

1303class NTPInfoMonitor1(Packet): 

1304 """ 

1305 Structure used for returning monitor data. 

1306 """ 

1307 

1308 name = "InfoMonitor1" 

1309 fields_desc = [ 

1310 IntField("lasttime", 0), 

1311 IntField("firsttime", 0), 

1312 IntField("lastdrop", 0), 

1313 IntField("count", 0), 

1314 IPField("addr", "0.0.0.0"), 

1315 IPField("daddr", "0.0.0.0"), 

1316 IntField("flags", 0), 

1317 ShortField("port", 0), 

1318 ByteField("mode", 0), 

1319 ByteField("version", 0), 

1320 IntField("v6_flag", 0), 

1321 IntField("unused1", 0), 

1322 IP6Field("addr6", "::"), 

1323 IP6Field("daddr6", "::") 

1324 ] 

1325 

1326 

1327class NTPInfoAuth(Packet): 

1328 """ 

1329 Structure used to return information concerning the authentication module. 

1330 """ 

1331 

1332 name = "info_auth" 

1333 fields_desc = [ 

1334 IntField("timereset", 0), 

1335 IntField("numkeys", 0), 

1336 IntField("numfreekeys", 0), 

1337 IntField("keylookups", 0), 

1338 IntField("keynotfound", 0), 

1339 IntField("encryptions", 0), 

1340 IntField("decryptions", 0), 

1341 IntField("expired", 0), 

1342 IntField("keyuncached", 0), 

1343 ] 

1344 

1345 

1346class NTPConfTrap(Packet): 

1347 """ 

1348 Structure used to pass add/clear trap information to the client 

1349 """ 

1350 

1351 name = "conf_trap" 

1352 fields_desc = [ 

1353 IPField("local_address", "0.0.0.0"), 

1354 IPField("trap_address", "0.0.0.0"), 

1355 ShortField("trap_port", 0), 

1356 ShortField("unused", 0), 

1357 IntField("v6_flag", 0), 

1358 IP6Field("local_address6", "::"), 

1359 IP6Field("trap_address6", "::"), 

1360 ] 

1361 

1362 

1363class NTPInfoControl(Packet): 

1364 """ 

1365 Structure used to return statistics from the control module. 

1366 """ 

1367 

1368 name = "info_control" 

1369 fields_desc = [ 

1370 IntField("ctltimereset", 0), 

1371 IntField("numctlreq", 0), 

1372 IntField("numctlbadpkts", 0), 

1373 IntField("numctlresponses", 0), 

1374 IntField("numctlfrags", 0), 

1375 IntField("numctlerrors", 0), 

1376 IntField("numctltooshort", 0), 

1377 IntField("numctlinputresp", 0), 

1378 IntField("numctlinputfrag", 0), 

1379 IntField("numctlinputerr", 0), 

1380 IntField("numctlbadoffset", 0), 

1381 IntField("numctlbadversion", 0), 

1382 IntField("numctldatatooshort", 0), 

1383 IntField("numctlbadop", 0), 

1384 IntField("numasyncmsgs", 0), 

1385 ] 

1386 

1387 

1388# ntp_request.h 

1389_ntpd_private_errors = { 

1390 0: "no error", 

1391 1: "incompatible implementation number", 

1392 2: "unimplemented request code", 

1393 3: "format error (wrong data items, data size, packet size etc.)", 

1394 4: "no data available (e.g. request for details on unknown peer)", 

1395 5: "I don\"t know", 

1396 6: "I don\"t know", 

1397 7: "authentication failure (i.e. permission denied)", 

1398} 

1399 

1400 

1401# dict mapping request codes to the right response data class 

1402_private_data_objects = { 

1403 0: NTPInfoPeerList, # "REQ_PEER_LIST", 

1404 1: NTPInfoPeerSummary, # "REQ_PEER_LIST_SUM", 

1405 2: NTPInfoPeer, # "REQ_PEER_INFO", 

1406 3: NTPInfoPeerStats, # "REQ_PEER_STATS", 

1407 4: NTPInfoSys, # "REQ_SYS_INFO", 

1408 5: NTPInfoSysStats, # "REQ_SYS_STATS", 

1409 6: NTPInfoIOStats, # "REQ_IO_STATS", 

1410 7: NTPInfoMemStats, # "REQ_MEM_STATS", 

1411 8: NTPInfoLoop, # "REQ_LOOP_INFO", 

1412 9: NTPInfoTimerStats, # "REQ_TIMER_STATS", 

1413 10: NTPConfPeer, # "REQ_CONFIG", 

1414 11: NTPConfUnpeer, # "REQ_UNCONFIG", 

1415 28: NTPInfoAuth, # "REQ_AUTHINFO", 

1416 30: NTPConfTrap, # "REQ_ADD_TRAP", 

1417 34: NTPInfoControl, # "REQ_GET_CTLSTATS", 

1418 38: NTPInfoKernel, # "REQ_GET_KERNEL", 

1419 42: NTPInfoMonitor1, # "REQ_MON_GETLIST_1", 

1420} 

1421 

1422 

1423class NTPPrivateRespPacketListField(PacketListField): 

1424 """ 

1425 PacketListField handling the response data. 

1426 """ 

1427 

1428 def m2i(self, pkt, s): 

1429 ret = None 

1430 

1431 # info_if_stats 

1432 if pkt.request_code == 44 or pkt.request_code == 45: 

1433 is_v6 = struct.unpack("!I", s[48:52])[0] 

1434 ret = NTPInfoIfStatsIPv6(s) if is_v6 else NTPInfoIfStatsIPv4(s) 

1435 else: 

1436 ret = _private_data_objects.get(pkt.request_code, conf.raw_layer)(s) # noqa: E501 

1437 

1438 return ret 

1439 

1440 def getfield(self, pkt, s): 

1441 lst = [] 

1442 remain = s 

1443 length = pkt.data_item_size 

1444 if length > 0: 

1445 item_counter = 0 

1446 # Response payloads can be placed in several packets 

1447 while len(remain) >= pkt.data_item_size and item_counter < pkt.nb_items: # noqa: E501 

1448 current = remain[:length] 

1449 remain = remain[length:] 

1450 current_packet = self.m2i(pkt, current) 

1451 lst.append(current_packet) 

1452 item_counter += 1 

1453 

1454 return remain, lst 

1455 

1456 

1457class NTPPrivateReqPacket(Packet): 

1458 """ 

1459 Packet handling request data. 

1460 """ 

1461 

1462 name = "request data" 

1463 fields_desc = [StrField("req_data", "")] 

1464 

1465 

1466_request_codes = { 

1467 0: "REQ_PEER_LIST", 

1468 1: "REQ_PEER_LIST_SUM", 

1469 2: "REQ_PEER_INFO", 

1470 3: "REQ_PEER_STATS", 

1471 4: "REQ_SYS_INFO", 

1472 5: "REQ_SYS_STATS", 

1473 6: "REQ_IO_STATS", 

1474 7: "REQ_MEM_STATS", 

1475 8: "REQ_LOOP_INFO", 

1476 9: "REQ_TIMER_STATS", 

1477 10: "REQ_CONFIG", 

1478 11: "REQ_UNCONFIG", 

1479 12: "REQ_SET_SYS_FLAG", 

1480 13: "REQ_CLR_SYS_FLAG", 

1481 14: "REQ_MONITOR", 

1482 15: "REQ_NOMONITOR", 

1483 16: "REQ_GET_RESTRICT", 

1484 17: "REQ_RESADDFLAGS", 

1485 18: "REQ_RESSUBFLAGS", 

1486 19: "REQ_UNRESTRICT", 

1487 20: "REQ_MON_GETLIST", 

1488 21: "REQ_RESET_STATS", 

1489 22: "REQ_RESET_PEER", 

1490 23: "REQ_REREAD_KEYS", 

1491 24: "REQ_DO_DIRTY_HACK", 

1492 25: "REQ_DONT_DIRTY_HACK", 

1493 26: "REQ_TRUSTKEY", 

1494 27: "REQ_UNTRUSTKEY", 

1495 28: "REQ_AUTHINFO", 

1496 29: "REQ_TRAPS", 

1497 30: "REQ_ADD_TRAP", 

1498 31: "REQ_CLR_TRAP", 

1499 32: "REQ_REQUEST_KEY", 

1500 33: "REQ_CONTROL_KEY", 

1501 34: "REQ_GET_CTLSTATS", 

1502 35: "REQ_GET_LEAPINFO", 

1503 36: "REQ_GET_CLOCKINFO", 

1504 37: "REQ_SET_CLKFUDGE", 

1505 38: "REQ_GET_KERNEL", 

1506 39: "REQ_GET_CLKBUGINFO", 

1507 41: "REQ_SET_PRECISION", 

1508 42: "REQ_MON_GETLIST_1", 

1509 43: "REQ_HOSTNAME_ASSOCID", 

1510 44: "REQ_IF_STATS", 

1511 45: "REQ_IF_RELOAD" 

1512} 

1513 

1514 

1515class NTPPrivateReqPacketListField(PacketListField): 

1516 """ 

1517 Handles specific request packets. 

1518 """ 

1519 

1520 # See ntpdc/ntpdc.c and ntpdc/ntpdc_ops.c 

1521 

1522 def m2i(self, pkt, s): 

1523 ret = None 

1524 

1525 if pkt.request_code == 2 or pkt.request_code == 3: 

1526 # REQ_PEER_INFO (see ntpdc/ntpdc_ops.c: showpeer()) 

1527 # REQ_PEER_STATS (for request only) 

1528 ret = NTPInfoPeerList(s) 

1529 

1530 elif pkt.request_code == 10: 

1531 # REQ_CONFIG 

1532 ret = NTPConfPeer(s) 

1533 

1534 elif pkt.request_code == 11: 

1535 # REQ_CONFIG 

1536 ret = NTPConfUnpeer(s) 

1537 

1538 elif pkt.request_code == 17: 

1539 # REQ_RESADDFLAGS 

1540 ret = NTPConfRestrict(s) 

1541 

1542 elif pkt.request_code == 18: 

1543 # REQ_RESSUBFLAGS 

1544 ret = NTPConfRestrict(s) 

1545 

1546 elif pkt.request_code == 22: 

1547 # REQ_RESET_PEER 

1548 ret = NTPConfUnpeer(s) 

1549 

1550 elif pkt.request_code == 30 or pkt.request_code == 31: 

1551 # REQ_ADD_TRAP 

1552 ret = NTPConfTrap(s) 

1553 

1554 else: 

1555 ret = NTPPrivateReqPacket(s) 

1556 

1557 return ret 

1558 

1559 def getfield(self, pkt, s): 

1560 lst = [] 

1561 remain = s 

1562 length = pkt.data_item_size 

1563 if length > 0: 

1564 item_counter = 0 

1565 while len(remain) >= pkt.data_item_size * pkt.nb_items and item_counter < pkt.nb_items: # noqa: E501 

1566 current = remain[:length] 

1567 remain = remain[length:] 

1568 current_packet = self.m2i(pkt, current) 

1569 lst.append(current_packet) 

1570 item_counter += 1 

1571 

1572 # If "auth" bit is set, don't forget the padding bytes 

1573 if pkt.auth: 

1574 padding_end = len(remain) - _NTP_PRIVATE_REQ_PKT_TAIL_LEN 

1575 current_packet = conf.raw_layer(remain[:padding_end]) 

1576 lst.append(current_packet) 

1577 remain = remain[padding_end:] 

1578 

1579 return remain, lst 

1580 

1581 

1582class NTPPrivatePktTail(Packet): 

1583 """ 

1584 include/ntp_request.h 

1585 The req_pkt_tail structure is used by ntpd to adjust for different 

1586 packet sizes that may arrive. 

1587 """ 

1588 

1589 name = "req_pkt_tail" 

1590 fields_desc = [ 

1591 TimeStampField("tstamp", 0), 

1592 IntField("key_id", 0), 

1593 XStrFixedLenField( 

1594 "dgst", "", length_from=lambda x: _NTP_AUTH_MD5_DGST_SIZE) 

1595 ] 

1596 

1597 

1598class NTPPrivate(NTP): 

1599 """ 

1600 Packet handling the private (mode 7) messages. 

1601 """ 

1602 

1603 ######################################################################### 

1604 # ntpd source code: ntp_request.h 

1605 ######################################################################### 

1606 # 

1607 # A mode 7 packet is used exchanging data between an NTP server 

1608 # and a client for purposes other than time synchronization, e.g. 

1609 # monitoring, statistics gathering and configuration. A mode 7 

1610 # packet has the following format: 

1611 # 

1612 # 0 1 2 3 

1613 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 

1614 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

1615 # |R|M| VN | Mode|A| Sequence | Implementation| Req Code | 

1616 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

1617 # | Err | Number of data items | MBZ | Size of data item | 

1618 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

1619 # | | 

1620 # | Data (Minimum 0 octets, maximum 500 octets) | 

1621 # | | 

1622 # [...] | 

1623 # | | 

1624 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

1625 # | Encryption Keyid (when A bit set) | 

1626 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

1627 # | | 

1628 # | Message Authentication Code (when A bit set) | 

1629 # | | 

1630 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

1631 # 

1632 # where the fields are (note that the client sends requests, the server 

1633 # responses): 

1634 # 

1635 # Response Bit: This packet is a response (if clear, packet is a request). 

1636 # 

1637 # More Bit: Set for all packets but the last in a response which 

1638 # requires more than one packet. 

1639 # 

1640 # Version Number: 2 for current version 

1641 # 

1642 # Mode: Always 7 

1643 # 

1644 # Authenticated bit: If set, this packet is authenticated. 

1645 # 

1646 # Sequence number: For a multipacket response, contains the sequence 

1647 # number of this packet. 0 is the first in the sequence, 

1648 # 127 (or less) is the last. The More Bit must be set in 

1649 # all packets but the last. 

1650 # 

1651 # Implementation number: The number of the implementation this request code 

1652 # is defined by. An implementation number of zero is used 

1653 # for request codes/data formats which all implementations 

1654 # agree on. Implementation number 255 is reserved (for 

1655 # extensions, in case we run out). 

1656 # 

1657 # Request code: An implementation-specific code which specifies the 

1658 # operation to be (which has been) performed and/or the 

1659 # format and semantics of the data included in the packet. 

1660 # 

1661 # Err: Must be 0 for a request. For a response, holds an error 

1662 # code relating to the request. If nonzero, the operation 

1663 # requested wasn't performed. 

1664 # 

1665 # 0 - no error 

1666 # 1 - incompatible implementation number 

1667 # 2 - unimplemented request code 

1668 # 3 - format error (wrong data items, data size, packet size etc.) # noqa: E501 

1669 # 4 - no data available (e.g. request for details on unknown peer) # noqa: E501 

1670 # 5-6 I don"t know 

1671 # 7 - authentication failure (i.e. permission denied) 

1672 # 

1673 # Number of data items: number of data items in packet. 0 to 500 

1674 # 

1675 # MBZ: A reserved data field, must be zero in requests and responses. 

1676 # 

1677 # Size of data item: size of each data item in packet. 0 to 500 

1678 # 

1679 # Data: Variable sized area containing request/response data. For 

1680 # requests and responses the size in octets must be greater 

1681 # than or equal to the product of the number of data items 

1682 # and the size of a data item. For requests the data area 

1683 # must be exactly 40 octets in length. For responses the 

1684 # data area may be any length between 0 and 500 octets 

1685 # inclusive. 

1686 # 

1687 # Message Authentication Code: Same as NTP spec, in definition and function. # noqa: E501 

1688 # May optionally be included in requests which require 

1689 # authentication, is never included in responses. 

1690 # 

1691 # The version number, mode and keyid have the same function and are 

1692 # in the same location as a standard NTP packet. The request packet 

1693 # is the same size as a standard NTP packet to ease receive buffer 

1694 # management, and to allow the same encryption procedure to be used 

1695 # both on mode 7 and standard NTP packets. The mac is included when 

1696 # it is required that a request be authenticated, the keyid should be 

1697 # zero in requests in which the mac is not included. 

1698 # 

1699 # The data format depends on the implementation number/request code pair 

1700 # and whether the packet is a request or a response. The only requirement 

1701 # is that data items start in the octet immediately following the size 

1702 # word and that data items be concatenated without padding between (i.e. 

1703 # if the data area is larger than data_items*size, all padding is at 

1704 # the end). Padding is ignored, other than for encryption purposes. 

1705 # Implementations using encryption might want to include a time stamp 

1706 # or other data in the request packet padding. The key used for requests 

1707 # is implementation defined, but key 15 is suggested as a default. 

1708 ######################################################################### 

1709 # 

1710 

1711 name = "Private (mode 7)" 

1712 match_subclass = True 

1713 fields_desc = [ 

1714 BitField("response", 0, 1), 

1715 BitField("more", 0, 1), 

1716 BitField("version", 2, 3), 

1717 BitEnumField("mode", 7, 3, _ntp_modes), 

1718 BitField("auth", 0, 1), 

1719 BitField("seq", 0, 7), 

1720 ByteEnumField("implementation", 0, _implementations), 

1721 ByteEnumField("request_code", 0, _request_codes), 

1722 BitEnumField("err", 0, 4, _ntpd_private_errors), 

1723 BitField("nb_items", 0, 12), 

1724 BitField("mbz", 0, 4), 

1725 BitField("data_item_size", 0, 12), 

1726 ConditionalField( 

1727 NTPPrivateReqPacketListField( 

1728 "req_data", 

1729 [], 

1730 Packet, 

1731 length_from=lambda p: p.data_item_size, 

1732 count_from=lambda p: p.nb_items 

1733 ), 

1734 lambda p: p.response == 0 

1735 ), 

1736 # Responses 

1737 ConditionalField( 

1738 NTPPrivateRespPacketListField( 

1739 "data", 

1740 [], 

1741 Packet, 

1742 length_from=lambda p: p.data_item_size, 

1743 count_from=lambda p: p.nb_items 

1744 ), 

1745 lambda p: p.response == 1 

1746 ), 

1747 # Responses are not supposed to be authenticated 

1748 ConditionalField(PacketField("authenticator", "", NTPPrivatePktTail), 

1749 lambda p: p.response == 0 and p.auth == 1), 

1750 ] 

1751 

1752 

1753############################################################################## 

1754# Layer bindings 

1755############################################################################## 

1756 

1757bind_layers(UDP, NTP, {"sport": 123}) 

1758bind_layers(UDP, NTP, {"dport": 123}) 

1759bind_layers(UDP, NTP, {"sport": 123, "dport": 123})