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

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

301 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""" 

7PPP (Point to Point Protocol) 

8 

9[RFC 1661] 

10""" 

11 

12import struct 

13from scapy.config import conf 

14from scapy.data import DLT_PPP, DLT_PPP_SERIAL, DLT_PPP_ETHER, \ 

15 DLT_PPP_WITH_DIR 

16from scapy.compat import orb 

17from scapy.packet import Packet, bind_layers 

18from scapy.layers.eap import EAP 

19from scapy.layers.l2 import Ether, CookedLinux, GRE_PPTP 

20from scapy.layers.inet import IP 

21from scapy.layers.inet6 import IPv6 

22from scapy.fields import ( 

23 BitField, 

24 ByteEnumField, 

25 ByteField, 

26 ConditionalField, 

27 EnumField, 

28 FieldLenField, 

29 IPField, 

30 IntField, 

31 OUIField, 

32 PacketField, 

33 PacketListField, 

34 ShortEnumField, 

35 ShortField, 

36 StrLenField, 

37 XByteField, 

38 XShortField, 

39 XStrLenField, 

40) 

41 

42 

43class PPPoE(Packet): 

44 name = "PPP over Ethernet" 

45 fields_desc = [BitField("version", 1, 4), 

46 BitField("type", 1, 4), 

47 ByteEnumField("code", 0, {0: "Session"}), 

48 XShortField("sessionid", 0x0), 

49 ShortField("len", None)] 

50 

51 def post_build(self, p, pay): 

52 p += pay 

53 if self.len is None: 

54 tmp_len = len(p) - 6 

55 p = p[:4] + struct.pack("!H", tmp_len) + p[6:] 

56 return p 

57 

58 

59# PPPoE Active Discovery Code fields (RFC2516, RFC5578) 

60class PPPoED(PPPoE): 

61 name = "PPP over Ethernet Discovery" 

62 

63 code_list = {0x00: "PPP Session Stage", 

64 0x09: "PPPoE Active Discovery Initiation (PADI)", 

65 0x07: "PPPoE Active Discovery Offer (PADO)", 

66 0x0a: "PPPoE Active Discovery Session-Grant (PADG)", 

67 0x0b: "PPPoE Active Discovery Session-Credit Response (PADC)", 

68 0x0c: "PPPoE Active Discovery Quality (PADQ)", 

69 0x19: "PPPoE Active Discovery Request (PADR)", 

70 0x65: "PPPoE Active Discovery Session-confirmation (PADS)", 

71 0xa7: "PPPoE Active Discovery Terminate (PADT)"} 

72 

73 fields_desc = [BitField("version", 1, 4), 

74 BitField("type", 1, 4), 

75 ByteEnumField("code", 0x09, code_list), 

76 XShortField("sessionid", 0x0), 

77 ShortField("len", None)] 

78 

79 def extract_padding(self, s): 

80 return s[:self.len], s[self.len:] 

81 

82 def mysummary(self): 

83 return self.sprintf("%code%") 

84 

85 

86# PPPoE Tag types (RFC2516, RFC4638, RFC5578) 

87class PPPoETag(Packet): 

88 name = "PPPoE Tag" 

89 

90 tag_list = {0x0000: 'End-Of-List', 

91 0x0101: 'Service-Name', 

92 0x0102: 'AC-Name', 

93 0x0103: 'Host-Uniq', 

94 0x0104: 'AC-Cookie', 

95 0x0105: 'Vendor-Specific', 

96 0x0106: 'Credits', 

97 0x0107: 'Metrics', 

98 0x0108: 'Sequence Number', 

99 0x0109: 'Credit Scale Factor', 

100 0x0110: 'Relay-Session-Id', 

101 0x0120: 'PPP-Max-Payload', 

102 0x0201: 'Service-Name-Error', 

103 0x0202: 'AC-System-Error', 

104 0x0203: 'Generic-Error'} 

105 

106 fields_desc = [ 

107 ShortEnumField('tag_type', None, tag_list), 

108 FieldLenField('tag_len', None, length_of='tag_value', fmt='H'), 

109 StrLenField('tag_value', '', length_from=lambda pkt:pkt.tag_len) 

110 ] 

111 

112 def extract_padding(self, s): 

113 return '', s 

114 

115 

116class PPPoED_Tags(Packet): 

117 name = "PPPoE Tag List" 

118 fields_desc = [PacketListField('tag_list', None, PPPoETag)] 

119 

120 def mysummary(self): 

121 return "PPPoE Tags" + ", ".join( 

122 x.sprintf("%tag_type%") for x in self.tag_list 

123 ), [PPPoED] 

124 

125 

126_PPP_PROTOCOLS = { 

127 0x0001: "Padding Protocol", 

128 0x0003: "ROHC small-CID [RFC3095]", 

129 0x0005: "ROHC large-CID [RFC3095]", 

130 0x0021: "Internet Protocol version 4", 

131 0x0023: "OSI Network Layer", 

132 0x0025: "Xerox NS IDP", 

133 0x0027: "DECnet Phase IV", 

134 0x0029: "Appletalk", 

135 0x002b: "Novell IPX", 

136 0x002d: "Van Jacobson Compressed TCP/IP", 

137 0x002f: "Van Jacobson Uncompressed TCP/IP", 

138 0x0031: "Bridging PDU", 

139 0x0033: "Stream Protocol (ST-II)", 

140 0x0035: "Banyan Vines", 

141 0x0037: "reserved (until 1993) [Typo in RFC1172]", 

142 0x0039: "AppleTalk EDDP", 

143 0x003b: "AppleTalk SmartBuffered", 

144 0x003d: "Multi-Link [RFC1717]", 

145 0x003f: "NETBIOS Framing", 

146 0x0041: "Cisco Systems", 

147 0x0043: "Ascom Timeplex", 

148 0x0045: "Fujitsu Link Backup and Load Balancing (LBLB)", 

149 0x0047: "DCA Remote Lan", 

150 0x0049: "Serial Data Transport Protocol (PPP-SDTP)", 

151 0x004b: "SNA over 802.2", 

152 0x004d: "SNA", 

153 0x004f: "IPv6 Header Compression", 

154 0x0051: "KNX Bridging Data [ianp]", 

155 0x0053: "Encryption [Meyer]", 

156 0x0055: "Individual Link Encryption [Meyer]", 

157 0x0057: "Internet Protocol version 6 [Hinden]", 

158 0x0059: "PPP Muxing [RFC3153]", 

159 0x005b: "Vendor-Specific Network Protocol (VSNP) [RFC3772]", 

160 0x0061: "RTP IPHC Full Header [RFC3544]", 

161 0x0063: "RTP IPHC Compressed TCP [RFC3544]", 

162 0x0065: "RTP IPHC Compressed Non TCP [RFC3544]", 

163 0x0067: "RTP IPHC Compressed UDP 8 [RFC3544]", 

164 0x0069: "RTP IPHC Compressed RTP 8 [RFC3544]", 

165 0x006f: "Stampede Bridging", 

166 0x0071: "Reserved [Fox]", 

167 0x0073: "MP+ Protocol [Smith]", 

168 0x007d: "reserved (Control Escape) [RFC1661]", 

169 0x007f: "reserved (compression inefficient [RFC1662]", 

170 0x0081: "Reserved Until 20-Oct-2000 [IANA]", 

171 0x0083: "Reserved Until 20-Oct-2000 [IANA]", 

172 0x00c1: "NTCITS IPI [Ungar]", 

173 0x00cf: "reserved (PPP NLID)", 

174 0x00fb: "single link compression in multilink [RFC1962]", 

175 0x00fd: "compressed datagram [RFC1962]", 

176 0x00ff: "reserved (compression inefficient)", 

177 0x0201: "802.1d Hello Packets", 

178 0x0203: "IBM Source Routing BPDU", 

179 0x0205: "DEC LANBridge100 Spanning Tree", 

180 0x0207: "Cisco Discovery Protocol [Sastry]", 

181 0x0209: "Netcs Twin Routing [Korfmacher]", 

182 0x020b: "STP - Scheduled Transfer Protocol [Segal]", 

183 0x020d: "EDP - Extreme Discovery Protocol [Grosser]", 

184 0x0211: "Optical Supervisory Channel Protocol (OSCP)[Prasad]", 

185 0x0213: "Optical Supervisory Channel Protocol (OSCP)[Prasad]", 

186 0x0231: "Luxcom", 

187 0x0233: "Sigma Network Systems", 

188 0x0235: "Apple Client Server Protocol [Ridenour]", 

189 0x0281: "MPLS Unicast [RFC3032] ", 

190 0x0283: "MPLS Multicast [RFC3032]", 

191 0x0285: "IEEE p1284.4 standard - data packets [Batchelder]", 

192 0x0287: "ETSI TETRA Network Protocol Type 1 [Nieminen]", 

193 0x0289: "Multichannel Flow Treatment Protocol [McCann]", 

194 0x2063: "RTP IPHC Compressed TCP No Delta [RFC3544]", 

195 0x2065: "RTP IPHC Context State [RFC3544]", 

196 0x2067: "RTP IPHC Compressed UDP 16 [RFC3544]", 

197 0x2069: "RTP IPHC Compressed RTP 16 [RFC3544]", 

198 0x4001: "Cray Communications Control Protocol [Stage]", 

199 0x4003: "CDPD Mobile Network Registration Protocol [Quick]", 

200 0x4005: "Expand accelerator protocol [Rachmani]", 

201 0x4007: "ODSICP NCP [Arvind]", 

202 0x4009: "DOCSIS DLL [Gaedtke]", 

203 0x400B: "Cetacean Network Detection Protocol [Siller]", 

204 0x4021: "Stacker LZS [Simpson]", 

205 0x4023: "RefTek Protocol [Banfill]", 

206 0x4025: "Fibre Channel [Rajagopal]", 

207 0x4027: "EMIT Protocols [Eastham]", 

208 0x405b: "Vendor-Specific Protocol (VSP) [RFC3772]", 

209 0x8021: "Internet Protocol Control Protocol", 

210 0x8023: "OSI Network Layer Control Protocol", 

211 0x8025: "Xerox NS IDP Control Protocol", 

212 0x8027: "DECnet Phase IV Control Protocol", 

213 0x8029: "Appletalk Control Protocol", 

214 0x802b: "Novell IPX Control Protocol", 

215 0x802d: "reserved", 

216 0x802f: "reserved", 

217 0x8031: "Bridging NCP", 

218 0x8033: "Stream Protocol Control Protocol", 

219 0x8035: "Banyan Vines Control Protocol", 

220 0x8037: "reserved (until 1993)", 

221 0x8039: "reserved", 

222 0x803b: "reserved", 

223 0x803d: "Multi-Link Control Protocol", 

224 0x803f: "NETBIOS Framing Control Protocol", 

225 0x8041: "Cisco Systems Control Protocol", 

226 0x8043: "Ascom Timeplex", 

227 0x8045: "Fujitsu LBLB Control Protocol", 

228 0x8047: "DCA Remote Lan Network Control Protocol (RLNCP)", 

229 0x8049: "Serial Data Control Protocol (PPP-SDCP)", 

230 0x804b: "SNA over 802.2 Control Protocol", 

231 0x804d: "SNA Control Protocol", 

232 0x804f: "IP6 Header Compression Control Protocol", 

233 0x8051: "KNX Bridging Control Protocol [ianp]", 

234 0x8053: "Encryption Control Protocol [Meyer]", 

235 0x8055: "Individual Link Encryption Control Protocol [Meyer]", 

236 0x8057: "IPv6 Control Protovol [Hinden]", 

237 0x8059: "PPP Muxing Control Protocol [RFC3153]", 

238 0x805b: "Vendor-Specific Network Control Protocol (VSNCP) [RFC3772]", 

239 0x806f: "Stampede Bridging Control Protocol", 

240 0x8073: "MP+ Control Protocol [Smith]", 

241 0x8071: "Reserved [Fox]", 

242 0x807d: "Not Used - reserved [RFC1661]", 

243 0x8081: "Reserved Until 20-Oct-2000 [IANA]", 

244 0x8083: "Reserved Until 20-Oct-2000 [IANA]", 

245 0x80c1: "NTCITS IPI Control Protocol [Ungar]", 

246 0x80cf: "Not Used - reserved [RFC1661]", 

247 0x80fb: "single link compression in multilink control [RFC1962]", 

248 0x80fd: "Compression Control Protocol [RFC1962]", 

249 0x80ff: "Not Used - reserved [RFC1661]", 

250 0x8207: "Cisco Discovery Protocol Control [Sastry]", 

251 0x8209: "Netcs Twin Routing [Korfmacher]", 

252 0x820b: "STP - Control Protocol [Segal]", 

253 0x820d: "EDPCP - Extreme Discovery Protocol Ctrl Prtcl [Grosser]", 

254 0x8235: "Apple Client Server Protocol Control [Ridenour]", 

255 0x8281: "MPLSCP [RFC3032]", 

256 0x8285: "IEEE p1284.4 standard - Protocol Control [Batchelder]", 

257 0x8287: "ETSI TETRA TNP1 Control Protocol [Nieminen]", 

258 0x8289: "Multichannel Flow Treatment Protocol [McCann]", 

259 0xc021: "Link Control Protocol", 

260 0xc023: "Password Authentication Protocol", 

261 0xc025: "Link Quality Report", 

262 0xc027: "Shiva Password Authentication Protocol", 

263 0xc029: "CallBack Control Protocol (CBCP)", 

264 0xc02b: "BACP Bandwidth Allocation Control Protocol [RFC2125]", 

265 0xc02d: "BAP [RFC2125]", 

266 0xc05b: "Vendor-Specific Authentication Protocol (VSAP) [RFC3772]", 

267 0xc081: "Container Control Protocol [KEN]", 

268 0xc223: "Challenge Handshake Authentication Protocol", 

269 0xc225: "RSA Authentication Protocol [Narayana]", 

270 0xc227: "Extensible Authentication Protocol [RFC2284]", 

271 0xc229: "Mitsubishi Security Info Exch Ptcl (SIEP) [Seno]", 

272 0xc26f: "Stampede Bridging Authorization Protocol", 

273 0xc281: "Proprietary Authentication Protocol [KEN]", 

274 0xc283: "Proprietary Authentication Protocol [Tackabury]", 

275 0xc481: "Proprietary Node ID Authentication Protocol [KEN]", 

276} 

277 

278 

279class HDLC(Packet): 

280 fields_desc = [XByteField("address", 0xff), 

281 XByteField("control", 0x03)] 

282 

283 

284# LINKTYPE_PPP_WITH_DIR 

285class DIR_PPP(Packet): 

286 fields_desc = [ByteEnumField("direction", 0, ["received", "sent"])] 

287 

288 

289class _PPPProtoField(EnumField): 

290 """ 

291 A field that can be either Byte or Short, depending on the PPP RFC. 

292 

293 See RFC 1661 section 2 

294 <https://tools.ietf.org/html/rfc1661#section-2> 

295 

296 The generated proto field is two bytes when not specified, or when specified 

297 as an integer or a string: 

298 PPP() 

299 PPP(proto=0x21) 

300 PPP(proto="Internet Protocol version 4") 

301 To explicitly forge a one byte proto field, use the bytes representation: 

302 PPP(proto=b'\x21') 

303 """ 

304 def getfield(self, pkt, s): 

305 if ord(s[:1]) & 0x01: 

306 self.fmt = "!B" 

307 self.sz = 1 

308 else: 

309 self.fmt = "!H" 

310 self.sz = 2 

311 self.struct = struct.Struct(self.fmt) 

312 return super(_PPPProtoField, self).getfield(pkt, s) 

313 

314 def addfield(self, pkt, s, val): 

315 if isinstance(val, bytes): 

316 if len(val) == 1: 

317 fmt, sz = "!B", 1 

318 elif len(val) == 2: 

319 fmt, sz = "!H", 2 

320 else: 

321 raise TypeError('Invalid length for PPP proto') 

322 val = struct.Struct(fmt).unpack(val)[0] 

323 else: 

324 fmt, sz = "!H", 2 

325 self.fmt = fmt 

326 self.sz = sz 

327 self.struct = struct.Struct(self.fmt) 

328 return super(_PPPProtoField, self).addfield(pkt, s, val) 

329 

330 

331class PPP(Packet): 

332 name = "PPP Link Layer" 

333 fields_desc = [_PPPProtoField("proto", 0x0021, _PPP_PROTOCOLS)] 

334 

335 @classmethod 

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

337 if _pkt and _pkt[:1] == b'\xff': 

338 return HDLC 

339 return cls 

340 

341 

342_PPP_conftypes = {1: "Configure-Request", 

343 2: "Configure-Ack", 

344 3: "Configure-Nak", 

345 4: "Configure-Reject", 

346 5: "Terminate-Request", 

347 6: "Terminate-Ack", 

348 7: "Code-Reject", 

349 8: "Protocol-Reject", 

350 9: "Echo-Request", 

351 10: "Echo-Reply", 

352 11: "Discard-Request", 

353 14: "Reset-Request", 

354 15: "Reset-Ack", 

355 } 

356 

357 

358# PPP IPCP stuff (RFC 1332) 

359 

360# All IPCP options are defined below (names and associated classes) 

361_PPP_ipcpopttypes = {1: "IP-Addresses (Deprecated)", 

362 2: "IP-Compression-Protocol", 

363 3: "IP-Address", 

364 # not implemented, present for completeness 

365 4: "Mobile-IPv4", 

366 129: "Primary-DNS-Address", 

367 130: "Primary-NBNS-Address", 

368 131: "Secondary-DNS-Address", 

369 132: "Secondary-NBNS-Address"} 

370 

371 

372class PPP_IPCP_Option(Packet): 

373 name = "PPP IPCP Option" 

374 fields_desc = [ 

375 ByteEnumField("type", None, _PPP_ipcpopttypes), 

376 FieldLenField("len", None, length_of="data", fmt="B", 

377 adjust=lambda _, val: val + 2), 

378 StrLenField("data", "", length_from=lambda pkt: max(0, pkt.len - 2)), 

379 ] 

380 

381 def extract_padding(self, pay): 

382 return b"", pay 

383 

384 registered_options = {} 

385 

386 @classmethod 

387 def register_variant(cls): 

388 cls.registered_options[cls.type.default] = cls 

389 

390 @classmethod 

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

392 if _pkt: 

393 o = orb(_pkt[0]) 

394 return cls.registered_options.get(o, cls) 

395 return cls 

396 

397 

398class PPP_IPCP_Option_IPAddress(PPP_IPCP_Option): 

399 name = "PPP IPCP Option: IP Address" 

400 fields_desc = [ 

401 ByteEnumField("type", 3, _PPP_ipcpopttypes), 

402 FieldLenField("len", None, length_of="data", fmt="B", 

403 adjust=lambda _, val: val + 2), 

404 IPField("data", "0.0.0.0"), 

405 StrLenField("garbage", "", length_from=lambda pkt: pkt.len - 6), 

406 ] 

407 

408 

409class PPP_IPCP_Option_DNS1(PPP_IPCP_Option_IPAddress): 

410 name = "PPP IPCP Option: DNS1 Address" 

411 type = 129 

412 

413 

414class PPP_IPCP_Option_DNS2(PPP_IPCP_Option_IPAddress): 

415 name = "PPP IPCP Option: DNS2 Address" 

416 type = 131 

417 

418 

419class PPP_IPCP_Option_NBNS1(PPP_IPCP_Option_IPAddress): 

420 name = "PPP IPCP Option: NBNS1 Address" 

421 type = 130 

422 

423 

424class PPP_IPCP_Option_NBNS2(PPP_IPCP_Option_IPAddress): 

425 name = "PPP IPCP Option: NBNS2 Address" 

426 type = 132 

427 

428 

429class PPP_IPCP(Packet): 

430 fields_desc = [ 

431 ByteEnumField("code", 1, _PPP_conftypes), 

432 XByteField("id", 0), 

433 FieldLenField("len", None, fmt="H", length_of="options", 

434 adjust=lambda _, val: val + 4), 

435 PacketListField("options", [], PPP_IPCP_Option, 

436 length_from=lambda pkt: pkt.len - 4) 

437 ] 

438 

439 

440# ECP 

441 

442_PPP_ecpopttypes = {0: "OUI", 

443 1: "DESE", } 

444 

445 

446class PPP_ECP_Option(Packet): 

447 name = "PPP ECP Option" 

448 fields_desc = [ 

449 ByteEnumField("type", None, _PPP_ecpopttypes), 

450 FieldLenField("len", None, length_of="data", fmt="B", 

451 adjust=lambda _, val: val + 2), 

452 StrLenField("data", "", length_from=lambda pkt: max(0, pkt.len - 2)), 

453 ] 

454 

455 def extract_padding(self, pay): 

456 return b"", pay 

457 

458 registered_options = {} 

459 

460 @classmethod 

461 def register_variant(cls): 

462 cls.registered_options[cls.type.default] = cls 

463 

464 @classmethod 

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

466 if _pkt: 

467 o = orb(_pkt[0]) 

468 return cls.registered_options.get(o, cls) 

469 return cls 

470 

471 

472class PPP_ECP_Option_OUI(PPP_ECP_Option): 

473 fields_desc = [ 

474 ByteEnumField("type", 0, _PPP_ecpopttypes), 

475 FieldLenField("len", None, length_of="data", fmt="B", 

476 adjust=lambda _, val: val + 6), 

477 OUIField("oui", 0), 

478 ByteField("subtype", 0), 

479 StrLenField("data", "", length_from=lambda pkt: pkt.len - 6), 

480 ] 

481 

482 

483class PPP_ECP(Packet): 

484 fields_desc = [ 

485 ByteEnumField("code", 1, _PPP_conftypes), 

486 XByteField("id", 0), 

487 FieldLenField("len", None, fmt="H", length_of="options", 

488 adjust=lambda _, val: val + 4), 

489 PacketListField("options", [], PPP_ECP_Option, 

490 length_from=lambda pkt: pkt.len - 4), 

491 ] 

492 

493# Link Control Protocol (RFC 1661) 

494 

495 

496_PPP_lcptypes = {1: "Configure-Request", 

497 2: "Configure-Ack", 

498 3: "Configure-Nak", 

499 4: "Configure-Reject", 

500 5: "Terminate-Request", 

501 6: "Terminate-Ack", 

502 7: "Code-Reject", 

503 8: "Protocol-Reject", 

504 9: "Echo-Request", 

505 10: "Echo-Reply", 

506 11: "Discard-Request"} 

507 

508 

509class PPP_LCP(Packet): 

510 name = "PPP Link Control Protocol" 

511 fields_desc = [ 

512 ByteEnumField("code", 5, _PPP_lcptypes), 

513 XByteField("id", 0), 

514 FieldLenField("len", None, fmt="H", length_of="data", 

515 adjust=lambda _, val: val + 4), 

516 StrLenField("data", "", length_from=lambda pkt: pkt.len - 4), 

517 ] 

518 

519 def mysummary(self): 

520 return self.sprintf('LCP %code%') 

521 

522 def extract_padding(self, pay): 

523 return b"", pay 

524 

525 @classmethod 

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

527 if _pkt: 

528 o = orb(_pkt[0]) 

529 if o in [1, 2, 3, 4]: 

530 return PPP_LCP_Configure 

531 elif o in [5, 6]: 

532 return PPP_LCP_Terminate 

533 elif o == 7: 

534 return PPP_LCP_Code_Reject 

535 elif o == 8: 

536 return PPP_LCP_Protocol_Reject 

537 elif o in [9, 10]: 

538 return PPP_LCP_Echo 

539 elif o == 11: 

540 return PPP_LCP_Discard_Request 

541 else: 

542 return cls 

543 return cls 

544 

545 

546_PPP_lcp_optiontypes = {1: "Maximum-Receive-Unit", 

547 2: "Async-Control-Character-Map", 

548 3: "Authentication-protocol", 

549 4: "Quality-protocol", 

550 5: "Magic-number", 

551 7: "Protocol-Field-Compression", 

552 8: "Address-and-Control-Field-Compression", 

553 13: "Callback"} 

554 

555 

556class PPP_LCP_Option(Packet): 

557 name = "PPP LCP Option" 

558 fields_desc = [ 

559 ByteEnumField("type", None, _PPP_lcp_optiontypes), 

560 FieldLenField("len", None, fmt="B", length_of="data", 

561 adjust=lambda _, val: val + 2), 

562 StrLenField("data", None, length_from=lambda pkt: pkt.len - 2), 

563 ] 

564 

565 def extract_padding(self, pay): 

566 return b"", pay 

567 

568 registered_options = {} 

569 

570 @classmethod 

571 def register_variant(cls): 

572 cls.registered_options[cls.type.default] = cls 

573 

574 @classmethod 

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

576 if _pkt: 

577 o = orb(_pkt[0]) 

578 return cls.registered_options.get(o, cls) 

579 return cls 

580 

581 

582class PPP_LCP_MRU_Option(PPP_LCP_Option): 

583 fields_desc = [ByteEnumField("type", 1, _PPP_lcp_optiontypes), 

584 ByteField("len", 4), 

585 ShortField("max_recv_unit", 1500)] 

586 

587 

588_PPP_LCP_auth_protocols = { 

589 0xc023: "Password authentication protocol", 

590 0xc223: "Challenge-response authentication protocol", 

591 0xc227: "PPP Extensible authentication protocol", 

592} 

593 

594_PPP_LCP_CHAP_algorithms = { 

595 5: "MD5", 

596 6: "SHA1", 

597 128: "MS-CHAP", 

598 129: "MS-CHAP-v2", 

599} 

600 

601 

602class PPP_LCP_ACCM_Option(PPP_LCP_Option): 

603 fields_desc = [ 

604 ByteEnumField("type", 2, _PPP_lcp_optiontypes), 

605 ByteField("len", 6), 

606 BitField("accm", 0x00000000, 32), 

607 ] 

608 

609 

610def adjust_auth_len(pkt, x): 

611 if pkt.auth_protocol == 0xc223: 

612 return 5 

613 elif pkt.auth_protocol == 0xc023: 

614 return 4 

615 else: 

616 return x + 4 

617 

618 

619class PPP_LCP_Auth_Protocol_Option(PPP_LCP_Option): 

620 fields_desc = [ 

621 ByteEnumField("type", 3, _PPP_lcp_optiontypes), 

622 FieldLenField("len", None, fmt="B", length_of="data", 

623 adjust=adjust_auth_len), 

624 ShortEnumField("auth_protocol", 0xc023, _PPP_LCP_auth_protocols), 

625 ConditionalField( 

626 StrLenField("data", '', length_from=lambda pkt: pkt.len - 4), 

627 lambda pkt: pkt.auth_protocol != 0xc223 

628 ), 

629 ConditionalField( 

630 ByteEnumField("algorithm", 5, _PPP_LCP_CHAP_algorithms), 

631 lambda pkt: pkt.auth_protocol == 0xc223 

632 ), 

633 ] 

634 

635 

636_PPP_LCP_quality_protocols = {0xc025: "Link Quality Report"} 

637 

638 

639class PPP_LCP_Quality_Protocol_Option(PPP_LCP_Option): 

640 fields_desc = [ 

641 ByteEnumField("type", 4, _PPP_lcp_optiontypes), 

642 FieldLenField("len", None, fmt="B", length_of="data", 

643 adjust=lambda _, val: val + 4), 

644 ShortEnumField("quality_protocol", 0xc025, _PPP_LCP_quality_protocols), 

645 StrLenField("data", "", length_from=lambda pkt: pkt.len - 4), 

646 ] 

647 

648 

649class PPP_LCP_Magic_Number_Option(PPP_LCP_Option): 

650 fields_desc = [ 

651 ByteEnumField("type", 5, _PPP_lcp_optiontypes), 

652 ByteField("len", 6), 

653 IntField("magic_number", None), 

654 ] 

655 

656 

657_PPP_lcp_callback_operations = { 

658 0: "Location determined by user authentication", 

659 1: "Dialing string", 

660 2: "Location identifier", 

661 3: "E.164 number", 

662 4: "Distinguished name", 

663} 

664 

665 

666class PPP_LCP_Callback_Option(PPP_LCP_Option): 

667 fields_desc = [ 

668 ByteEnumField("type", 13, _PPP_lcp_optiontypes), 

669 FieldLenField("len", None, fmt="B", length_of="message", 

670 adjust=lambda _, val: val + 3), 

671 ByteEnumField("operation", 0, _PPP_lcp_callback_operations), 

672 StrLenField("message", "", length_from=lambda pkt: pkt.len - 3) 

673 ] 

674 

675 

676class PPP_LCP_Configure(PPP_LCP): 

677 fields_desc = [ 

678 ByteEnumField("code", 1, _PPP_lcptypes), 

679 XByteField("id", 0), 

680 FieldLenField("len", None, fmt="H", length_of="options", 

681 adjust=lambda _, val: val + 4), 

682 PacketListField("options", [], PPP_LCP_Option, 

683 length_from=lambda pkt: pkt.len - 4), 

684 ] 

685 

686 def answers(self, other): 

687 return ( 

688 isinstance(other, PPP_LCP_Configure) and self.code in [2, 3, 4] and 

689 other.code == 1 and other.id == self.id 

690 ) 

691 

692 

693class PPP_LCP_Terminate(PPP_LCP): 

694 

695 def answers(self, other): 

696 return ( 

697 isinstance(other, PPP_LCP_Terminate) and self.code == 6 and 

698 other.code == 5 and other.id == self.id 

699 ) 

700 

701 

702class PPP_LCP_Code_Reject(PPP_LCP): 

703 fields_desc = [ 

704 ByteEnumField("code", 7, _PPP_lcptypes), 

705 XByteField("id", 0), 

706 FieldLenField("len", None, fmt="H", length_of="rejected_packet", 

707 adjust=lambda _, val: val + 4), 

708 PacketField("rejected_packet", None, PPP_LCP), 

709 ] 

710 

711 

712class PPP_LCP_Protocol_Reject(PPP_LCP): 

713 fields_desc = [ 

714 ByteEnumField("code", 8, _PPP_lcptypes), 

715 XByteField("id", 0), 

716 FieldLenField("len", None, fmt="H", length_of="rejected_information", 

717 adjust=lambda _, val: val + 6), 

718 ShortEnumField("rejected_protocol", None, _PPP_PROTOCOLS), 

719 PacketField("rejected_information", None, Packet), 

720 ] 

721 

722 

723class PPP_LCP_Discard_Request(PPP_LCP): 

724 fields_desc = [ 

725 ByteEnumField("code", 11, _PPP_lcptypes), 

726 XByteField("id", 0), 

727 FieldLenField("len", None, fmt="H", length_of="data", 

728 adjust=lambda _, val: val + 8), 

729 IntField("magic_number", None), 

730 StrLenField("data", "", length_from=lambda pkt: pkt.len - 8), 

731 ] 

732 

733 

734class PPP_LCP_Echo(PPP_LCP_Discard_Request): 

735 code = 9 

736 

737 def answers(self, other): 

738 return ( 

739 isinstance(other, PPP_LCP_Echo) and self.code == 10 and 

740 other.code == 9 and self.id == other.id 

741 ) 

742 

743 

744# Password authentication protocol (RFC 1334) 

745 

746 

747_PPP_paptypes = {1: "Authenticate-Request", 

748 2: "Authenticate-Ack", 

749 3: "Authenticate-Nak"} 

750 

751 

752class PPP_PAP(Packet): 

753 name = "PPP Password Authentication Protocol" 

754 fields_desc = [ 

755 ByteEnumField("code", 1, _PPP_paptypes), 

756 XByteField("id", 0), 

757 FieldLenField("len", None, fmt="!H", length_of="data", 

758 adjust=lambda _, val: val + 4), 

759 StrLenField("data", "", length_from=lambda pkt: pkt.len - 4), 

760 ] 

761 

762 @classmethod 

763 def dispatch_hook(cls, _pkt=None, *_, **kargs): 

764 code = None 

765 if _pkt: 

766 code = orb(_pkt[0]) 

767 elif "code" in kargs: 

768 code = kargs["code"] 

769 if isinstance(code, str): 

770 code = cls.fields_desc[0].s2i[code] 

771 

772 if code == 1: 

773 return PPP_PAP_Request 

774 elif code in [2, 3]: 

775 return PPP_PAP_Response 

776 return cls 

777 

778 def extract_padding(self, pay): 

779 return "", pay 

780 

781 

782class PPP_PAP_Request(PPP_PAP): 

783 fields_desc = [ 

784 ByteEnumField("code", 1, _PPP_paptypes), 

785 XByteField("id", 0), 

786 FieldLenField("len", None, fmt="!H", length_of="username", 

787 adjust=lambda pkt, val: val + 6 + len(pkt.password)), 

788 FieldLenField("username_len", None, fmt="B", length_of="username"), 

789 StrLenField("username", None, 

790 length_from=lambda pkt: pkt.username_len), 

791 FieldLenField("passwd_len", None, fmt="B", length_of="password"), 

792 StrLenField("password", None, length_from=lambda pkt: pkt.passwd_len), 

793 ] 

794 

795 def mysummary(self): 

796 return self.sprintf("PAP-Request username=%PPP_PAP_Request.username%" 

797 " password=%PPP_PAP_Request.password%") 

798 

799 

800class PPP_PAP_Response(PPP_PAP): 

801 fields_desc = [ 

802 ByteEnumField("code", 2, _PPP_paptypes), 

803 XByteField("id", 0), 

804 FieldLenField("len", None, fmt="!H", length_of="message", 

805 adjust=lambda _, val: val + 5), 

806 FieldLenField("msg_len", None, fmt="B", length_of="message"), 

807 StrLenField("message", "", length_from=lambda pkt: pkt.msg_len), 

808 ] 

809 

810 def answers(self, other): 

811 return isinstance(other, PPP_PAP_Request) and other.id == self.id 

812 

813 def mysummary(self): 

814 res = "PAP-Ack" if self.code == 2 else "PAP-Nak" 

815 if self.msg_len > 0: 

816 res += self.sprintf(" msg=%PPP_PAP_Response.message%") 

817 return res 

818 

819 

820# Challenge Handshake Authentication protocol (RFC1994) 

821 

822_PPP_chaptypes = {1: "Challenge", 

823 2: "Response", 

824 3: "Success", 

825 4: "Failure"} 

826 

827 

828class PPP_CHAP(Packet): 

829 name = "PPP Challenge Handshake Authentication Protocol" 

830 fields_desc = [ 

831 ByteEnumField("code", 1, _PPP_chaptypes), 

832 XByteField("id", 0), 

833 FieldLenField("len", None, fmt="!H", length_of="data", 

834 adjust=lambda _, val: val + 4), 

835 StrLenField("data", "", length_from=lambda pkt: pkt.len - 4), 

836 ] 

837 

838 def answers(self, other): 

839 return isinstance(other, PPP_CHAP_ChallengeResponse) \ 

840 and other.code == 2 and self.code in (3, 4) \ 

841 and self.id == other.id 

842 

843 @classmethod 

844 def dispatch_hook(cls, _pkt=None, *_, **kargs): 

845 code = None 

846 if _pkt: 

847 code = orb(_pkt[0]) 

848 elif "code" in kargs: 

849 code = kargs["code"] 

850 if isinstance(code, str): 

851 code = cls.fields_desc[0].s2i[code] 

852 

853 if code in (1, 2): 

854 return PPP_CHAP_ChallengeResponse 

855 return cls 

856 

857 def extract_padding(self, pay): 

858 return "", pay 

859 

860 def mysummary(self): 

861 if self.code == 3: 

862 return self.sprintf("CHAP Success message=%PPP_CHAP.data%") 

863 elif self.code == 4: 

864 return self.sprintf("CHAP Failure message=%PPP_CHAP.data%") 

865 

866 

867class PPP_CHAP_ChallengeResponse(PPP_CHAP): 

868 fields_desc = [ 

869 ByteEnumField("code", 1, _PPP_chaptypes), 

870 XByteField("id", 0), 

871 FieldLenField( 

872 "len", None, fmt="!H", length_of="value", 

873 adjust=lambda pkt, val: val + len(pkt.optional_name) + 5, 

874 ), 

875 FieldLenField("value_size", None, fmt="B", length_of="value"), 

876 XStrLenField("value", b'\x00\x00\x00\x00\x00\x00\x00\x00', 

877 length_from=lambda pkt: pkt.value_size), 

878 StrLenField("optional_name", "", 

879 length_from=lambda pkt: pkt.len - pkt.value_size - 5), 

880 ] 

881 

882 def answers(self, other): 

883 return isinstance(other, PPP_CHAP_ChallengeResponse) \ 

884 and other.code == 1 and self.code == 2 and self.id == other.id 

885 

886 def mysummary(self): 

887 if self.code == 1: 

888 return self.sprintf( 

889 "CHAP challenge=0x%PPP_CHAP_ChallengeResponse.value% " 

890 "optional_name=%PPP_CHAP_ChallengeResponse.optional_name%" 

891 ) 

892 elif self.code == 2: 

893 return self.sprintf( 

894 "CHAP response=0x%PPP_CHAP_ChallengeResponse.value% " 

895 "optional_name=%PPP_CHAP_ChallengeResponse.optional_name%" 

896 ) 

897 else: 

898 return super(PPP_CHAP_ChallengeResponse, self).mysummary() 

899 

900 

901bind_layers(PPPoED, PPPoED_Tags, type=1) 

902bind_layers(Ether, PPPoED, type=0x8863) 

903bind_layers(Ether, PPPoE, type=0x8864) 

904bind_layers(CookedLinux, PPPoED, proto=0x8863) 

905bind_layers(CookedLinux, PPPoE, proto=0x8864) 

906bind_layers(PPPoE, PPP, code=0) 

907bind_layers(HDLC, PPP,) 

908bind_layers(DIR_PPP, PPP) 

909bind_layers(PPP, EAP, proto=0xc227) 

910bind_layers(PPP, IP, proto=0x0021) 

911bind_layers(PPP, IPv6, proto=0x0057) 

912bind_layers(PPP, PPP_CHAP, proto=0xc223) 

913bind_layers(PPP, PPP_IPCP, proto=0x8021) 

914bind_layers(PPP, PPP_ECP, proto=0x8053) 

915bind_layers(PPP, PPP_LCP, proto=0xc021) 

916bind_layers(PPP, PPP_PAP, proto=0xc023) 

917bind_layers(Ether, PPP_IPCP, type=0x8021) 

918bind_layers(Ether, PPP_ECP, type=0x8053) 

919bind_layers(GRE_PPTP, PPP, proto=0x880b) 

920 

921 

922conf.l2types.register(DLT_PPP, PPP) 

923conf.l2types.register(DLT_PPP_SERIAL, HDLC) 

924conf.l2types.register(DLT_PPP_ETHER, PPPoE) 

925conf.l2types.register(DLT_PPP_WITH_DIR, DIR_PPP)