• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1## This file is part of Scapy
2## See http://www.secdev.org/projects/scapy for more informations
3## Copyright (C) Philippe Biondi <phil@secdev.org>
4## This program is published under a GPLv2 license
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
15from scapy.compat import *
16from scapy.packet import Packet, bind_layers
17from scapy.layers.eap import EAP
18from scapy.layers.l2 import Ether, CookedLinux, GRE_PPTP
19from scapy.layers.inet import IP
20from scapy.layers.inet6 import IPv6
21from scapy.fields import BitField, ByteEnumField, ByteField, \
22    ConditionalField, FieldLenField, IntField, IPField, \
23    PacketListField, PacketField, ShortEnumField, ShortField, \
24    StrFixedLenField, StrLenField, XByteField, XShortField, XStrLenField
25
26
27class PPPoE(Packet):
28    name = "PPP over Ethernet"
29    fields_desc = [ BitField("version", 1, 4),
30                    BitField("type", 1, 4),
31                    ByteEnumField("code", 0, {0:"Session"}),
32                    XShortField("sessionid", 0x0),
33                    ShortField("len", None) ]
34
35    def post_build(self, p, pay):
36        p += pay
37        if self.len is None:
38            l = len(p)-6
39            p = p[:4]+struct.pack("!H", l)+p[6:]
40        return p
41
42class PPPoED(PPPoE):
43    name = "PPP over Ethernet Discovery"
44    fields_desc = [ BitField("version", 1, 4),
45                    BitField("type", 1, 4),
46                    ByteEnumField("code", 0x09, {0x09:"PADI",0x07:"PADO",0x19:"PADR",0x65:"PADS",0xa7:"PADT"}),
47                    XShortField("sessionid", 0x0),
48                    ShortField("len", None) ]
49
50
51_PPP_proto = { 0x0001: "Padding Protocol",
52               0x0003: "ROHC small-CID [RFC3095]",
53               0x0005: "ROHC large-CID [RFC3095]",
54               0x0021: "Internet Protocol version 4",
55               0x0023: "OSI Network Layer",
56               0x0025: "Xerox NS IDP",
57               0x0027: "DECnet Phase IV",
58               0x0029: "Appletalk",
59               0x002b: "Novell IPX",
60               0x002d: "Van Jacobson Compressed TCP/IP",
61               0x002f: "Van Jacobson Uncompressed TCP/IP",
62               0x0031: "Bridging PDU",
63               0x0033: "Stream Protocol (ST-II)",
64               0x0035: "Banyan Vines",
65               0x0037: "reserved (until 1993) [Typo in RFC1172]",
66               0x0039: "AppleTalk EDDP",
67               0x003b: "AppleTalk SmartBuffered",
68               0x003d: "Multi-Link [RFC1717]",
69               0x003f: "NETBIOS Framing",
70               0x0041: "Cisco Systems",
71               0x0043: "Ascom Timeplex",
72               0x0045: "Fujitsu Link Backup and Load Balancing (LBLB)",
73               0x0047: "DCA Remote Lan",
74               0x0049: "Serial Data Transport Protocol (PPP-SDTP)",
75               0x004b: "SNA over 802.2",
76               0x004d: "SNA",
77               0x004f: "IPv6 Header Compression",
78               0x0051: "KNX Bridging Data [ianp]",
79               0x0053: "Encryption [Meyer]",
80               0x0055: "Individual Link Encryption [Meyer]",
81               0x0057: "Internet Protocol version 6 [Hinden]",
82               0x0059: "PPP Muxing [RFC3153]",
83               0x005b: "Vendor-Specific Network Protocol (VSNP) [RFC3772]",
84               0x0061: "RTP IPHC Full Header [RFC3544]",
85               0x0063: "RTP IPHC Compressed TCP [RFC3544]",
86               0x0065: "RTP IPHC Compressed Non TCP [RFC3544]",
87               0x0067: "RTP IPHC Compressed UDP 8 [RFC3544]",
88               0x0069: "RTP IPHC Compressed RTP 8 [RFC3544]",
89               0x006f: "Stampede Bridging",
90               0x0071: "Reserved [Fox]",
91               0x0073: "MP+ Protocol [Smith]",
92               0x007d: "reserved (Control Escape) [RFC1661]",
93               0x007f: "reserved (compression inefficient [RFC1662]",
94               0x0081: "Reserved Until 20-Oct-2000 [IANA]",
95               0x0083: "Reserved Until 20-Oct-2000 [IANA]",
96               0x00c1: "NTCITS IPI [Ungar]",
97               0x00cf: "reserved (PPP NLID)",
98               0x00fb: "single link compression in multilink [RFC1962]",
99               0x00fd: "compressed datagram [RFC1962]",
100               0x00ff: "reserved (compression inefficient)",
101               0x0201: "802.1d Hello Packets",
102               0x0203: "IBM Source Routing BPDU",
103               0x0205: "DEC LANBridge100 Spanning Tree",
104               0x0207: "Cisco Discovery Protocol [Sastry]",
105               0x0209: "Netcs Twin Routing [Korfmacher]",
106               0x020b: "STP - Scheduled Transfer Protocol [Segal]",
107               0x020d: "EDP - Extreme Discovery Protocol [Grosser]",
108               0x0211: "Optical Supervisory Channel Protocol (OSCP)[Prasad]",
109               0x0213: "Optical Supervisory Channel Protocol (OSCP)[Prasad]",
110               0x0231: "Luxcom",
111               0x0233: "Sigma Network Systems",
112               0x0235: "Apple Client Server Protocol [Ridenour]",
113               0x0281: "MPLS Unicast [RFC3032]  ",
114               0x0283: "MPLS Multicast [RFC3032]",
115               0x0285: "IEEE p1284.4 standard - data packets [Batchelder]",
116               0x0287: "ETSI TETRA Network Protocol Type 1 [Nieminen]",
117               0x0289: "Multichannel Flow Treatment Protocol [McCann]",
118               0x2063: "RTP IPHC Compressed TCP No Delta [RFC3544]",
119               0x2065: "RTP IPHC Context State [RFC3544]",
120               0x2067: "RTP IPHC Compressed UDP 16 [RFC3544]",
121               0x2069: "RTP IPHC Compressed RTP 16 [RFC3544]",
122               0x4001: "Cray Communications Control Protocol [Stage]",
123               0x4003: "CDPD Mobile Network Registration Protocol [Quick]",
124               0x4005: "Expand accelerator protocol [Rachmani]",
125               0x4007: "ODSICP NCP [Arvind]",
126               0x4009: "DOCSIS DLL [Gaedtke]",
127               0x400B: "Cetacean Network Detection Protocol [Siller]",
128               0x4021: "Stacker LZS [Simpson]",
129               0x4023: "RefTek Protocol [Banfill]",
130               0x4025: "Fibre Channel [Rajagopal]",
131               0x4027: "EMIT Protocols [Eastham]",
132               0x405b: "Vendor-Specific Protocol (VSP) [RFC3772]",
133               0x8021: "Internet Protocol Control Protocol",
134               0x8023: "OSI Network Layer Control Protocol",
135               0x8025: "Xerox NS IDP Control Protocol",
136               0x8027: "DECnet Phase IV Control Protocol",
137               0x8029: "Appletalk Control Protocol",
138               0x802b: "Novell IPX Control Protocol",
139               0x802d: "reserved",
140               0x802f: "reserved",
141               0x8031: "Bridging NCP",
142               0x8033: "Stream Protocol Control Protocol",
143               0x8035: "Banyan Vines Control Protocol",
144               0x8037: "reserved (until 1993)",
145               0x8039: "reserved",
146               0x803b: "reserved",
147               0x803d: "Multi-Link Control Protocol",
148               0x803f: "NETBIOS Framing Control Protocol",
149               0x8041: "Cisco Systems Control Protocol",
150               0x8043: "Ascom Timeplex",
151               0x8045: "Fujitsu LBLB Control Protocol",
152               0x8047: "DCA Remote Lan Network Control Protocol (RLNCP)",
153               0x8049: "Serial Data Control Protocol (PPP-SDCP)",
154               0x804b: "SNA over 802.2 Control Protocol",
155               0x804d: "SNA Control Protocol",
156               0x804f: "IP6 Header Compression Control Protocol",
157               0x8051: "KNX Bridging Control Protocol [ianp]",
158               0x8053: "Encryption Control Protocol [Meyer]",
159               0x8055: "Individual Link Encryption Control Protocol [Meyer]",
160               0x8057: "IPv6 Control Protovol [Hinden]",
161               0x8059: "PPP Muxing Control Protocol [RFC3153]",
162               0x805b: "Vendor-Specific Network Control Protocol (VSNCP) [RFC3772]",
163               0x806f: "Stampede Bridging Control Protocol",
164               0x8073: "MP+ Control Protocol [Smith]",
165               0x8071: "Reserved [Fox]",
166               0x807d: "Not Used - reserved [RFC1661]",
167               0x8081: "Reserved Until 20-Oct-2000 [IANA]",
168               0x8083: "Reserved Until 20-Oct-2000 [IANA]",
169               0x80c1: "NTCITS IPI Control Protocol [Ungar]",
170               0x80cf: "Not Used - reserved [RFC1661]",
171               0x80fb: "single link compression in multilink control [RFC1962]",
172               0x80fd: "Compression Control Protocol [RFC1962]",
173               0x80ff: "Not Used - reserved [RFC1661]",
174               0x8207: "Cisco Discovery Protocol Control [Sastry]",
175               0x8209: "Netcs Twin Routing [Korfmacher]",
176               0x820b: "STP - Control Protocol [Segal]",
177               0x820d: "EDPCP - Extreme Discovery Protocol Ctrl Prtcl [Grosser]",
178               0x8235: "Apple Client Server Protocol Control [Ridenour]",
179               0x8281: "MPLSCP [RFC3032]",
180               0x8285: "IEEE p1284.4 standard - Protocol Control [Batchelder]",
181               0x8287: "ETSI TETRA TNP1 Control Protocol [Nieminen]",
182               0x8289: "Multichannel Flow Treatment Protocol [McCann]",
183               0xc021: "Link Control Protocol",
184               0xc023: "Password Authentication Protocol",
185               0xc025: "Link Quality Report",
186               0xc027: "Shiva Password Authentication Protocol",
187               0xc029: "CallBack Control Protocol (CBCP)",
188               0xc02b: "BACP Bandwidth Allocation Control Protocol [RFC2125]",
189               0xc02d: "BAP [RFC2125]",
190               0xc05b: "Vendor-Specific Authentication Protocol (VSAP) [RFC3772]",
191               0xc081: "Container Control Protocol [KEN]",
192               0xc223: "Challenge Handshake Authentication Protocol",
193               0xc225: "RSA Authentication Protocol [Narayana]",
194               0xc227: "Extensible Authentication Protocol [RFC2284]",
195               0xc229: "Mitsubishi Security Info Exch Ptcl (SIEP) [Seno]",
196               0xc26f: "Stampede Bridging Authorization Protocol",
197               0xc281: "Proprietary Authentication Protocol [KEN]",
198               0xc283: "Proprietary Authentication Protocol [Tackabury]",
199               0xc481: "Proprietary Node ID Authentication Protocol [KEN]"}
200
201
202class HDLC(Packet):
203    fields_desc = [ XByteField("address",0xff),
204                    XByteField("control",0x03)  ]
205
206class PPP(Packet):
207    name = "PPP Link Layer"
208    fields_desc = [ ShortEnumField("proto", 0x0021, _PPP_proto) ]
209    @classmethod
210    def dispatch_hook(cls, _pkt=None, *args, **kargs):
211        if _pkt and orb(_pkt[0]) == 0xff:
212            cls = HDLC
213        return cls
214
215_PPP_conftypes = { 1:"Configure-Request",
216                   2:"Configure-Ack",
217                   3:"Configure-Nak",
218                   4:"Configure-Reject",
219                   5:"Terminate-Request",
220                   6:"Terminate-Ack",
221                   7:"Code-Reject",
222                   8:"Protocol-Reject",
223                   9:"Echo-Request",
224                   10:"Echo-Reply",
225                   11:"Discard-Request",
226                   14:"Reset-Request",
227                   15:"Reset-Ack",
228                   }
229
230
231### PPP IPCP stuff (RFC 1332)
232
233# All IPCP options are defined below (names and associated classes)
234_PPP_ipcpopttypes = {     1:"IP-Addresses (Deprecated)",
235                          2:"IP-Compression-Protocol",
236                          3:"IP-Address",
237                          4:"Mobile-IPv4", # not implemented, present for completeness
238                          129:"Primary-DNS-Address",
239                          130:"Primary-NBNS-Address",
240                          131:"Secondary-DNS-Address",
241                          132:"Secondary-NBNS-Address"}
242
243
244class PPP_IPCP_Option(Packet):
245    name = "PPP IPCP Option"
246    fields_desc = [ ByteEnumField("type" , None , _PPP_ipcpopttypes),
247                    FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2),
248                    StrLenField("data", "", length_from=lambda p:max(0,p.len-2)) ]
249    def extract_padding(self, pay):
250        return b"",pay
251
252    registered_options = {}
253    @classmethod
254    def register_variant(cls):
255        cls.registered_options[cls.type.default] = cls
256    @classmethod
257    def dispatch_hook(cls, _pkt=None, *args, **kargs):
258        if _pkt:
259            o = orb(_pkt[0])
260            return cls.registered_options.get(o, cls)
261        return cls
262
263
264class PPP_IPCP_Option_IPAddress(PPP_IPCP_Option):
265    name = "PPP IPCP Option: IP Address"
266    fields_desc = [ ByteEnumField("type" , 3 , _PPP_ipcpopttypes),
267                    FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2),
268                    IPField("data","0.0.0.0"),
269                    ConditionalField(StrLenField("garbage","", length_from=lambda pkt:pkt.len-6), lambda p:p.len!=6) ]
270
271class PPP_IPCP_Option_DNS1(PPP_IPCP_Option):
272    name = "PPP IPCP Option: DNS1 Address"
273    fields_desc = [ ByteEnumField("type" , 129 , _PPP_ipcpopttypes),
274                    FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2),
275                    IPField("data","0.0.0.0"),
276                    ConditionalField(StrLenField("garbage","", length_from=lambda pkt:pkt.len-6), lambda p:p.len!=6) ]
277
278class PPP_IPCP_Option_DNS2(PPP_IPCP_Option):
279    name = "PPP IPCP Option: DNS2 Address"
280    fields_desc = [ ByteEnumField("type" , 131 , _PPP_ipcpopttypes),
281                    FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2),
282                    IPField("data","0.0.0.0"),
283                    ConditionalField(StrLenField("garbage","", length_from=lambda pkt:pkt.len-6), lambda p:p.len!=6) ]
284
285class PPP_IPCP_Option_NBNS1(PPP_IPCP_Option):
286    name = "PPP IPCP Option: NBNS1 Address"
287    fields_desc = [ ByteEnumField("type" , 130 , _PPP_ipcpopttypes),
288                    FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2),
289                    IPField("data","0.0.0.0"),
290                    ConditionalField(StrLenField("garbage","", length_from=lambda pkt:pkt.len-6), lambda p:p.len!=6) ]
291
292class PPP_IPCP_Option_NBNS2(PPP_IPCP_Option):
293    name = "PPP IPCP Option: NBNS2 Address"
294    fields_desc = [ ByteEnumField("type" , 132 , _PPP_ipcpopttypes),
295                    FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2),
296                    IPField("data","0.0.0.0"),
297                    ConditionalField(StrLenField("garbage","", length_from=lambda pkt:pkt.len-6), lambda p:p.len!=6) ]
298
299
300class PPP_IPCP(Packet):
301    fields_desc = [ ByteEnumField("code" , 1, _PPP_conftypes),
302                    XByteField("id", 0 ),
303                    FieldLenField("len" , None, fmt="H", length_of="options", adjust=lambda p,x:x+4 ),
304                    PacketListField("options", [],  PPP_IPCP_Option, length_from=lambda p:p.len-4,) ]
305
306
307### ECP
308
309_PPP_ecpopttypes = { 0:"OUI",
310                     1:"DESE", }
311
312class PPP_ECP_Option(Packet):
313    name = "PPP ECP Option"
314    fields_desc = [ ByteEnumField("type" , None , _PPP_ecpopttypes),
315                    FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2),
316                    StrLenField("data", "", length_from=lambda p:max(0,p.len-2)) ]
317    def extract_padding(self, pay):
318        return b"",pay
319
320    registered_options = {}
321    @classmethod
322    def register_variant(cls):
323        cls.registered_options[cls.type.default] = cls
324    @classmethod
325    def dispatch_hook(cls, _pkt=None, *args, **kargs):
326        if _pkt:
327            o = orb(_pkt[0])
328            return cls.registered_options.get(o, cls)
329        return cls
330
331class PPP_ECP_Option_OUI(PPP_ECP_Option):
332    fields_desc = [ ByteEnumField("type" , 0 , _PPP_ecpopttypes),
333                    FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+6),
334                    StrFixedLenField("oui","",3),
335                    ByteField("subtype",0),
336                    StrLenField("data", "", length_from=lambda p:p.len-6) ]
337
338
339
340class PPP_ECP(Packet):
341    fields_desc = [ ByteEnumField("code" , 1, _PPP_conftypes),
342                    XByteField("id", 0 ),
343                    FieldLenField("len" , None, fmt="H", length_of="options", adjust=lambda p,x:x+4 ),
344                    PacketListField("options", [],  PPP_ECP_Option, length_from=lambda p:p.len-4,) ]
345
346### Link Control Protocol (RFC 1661)
347
348_PPP_lcptypes = {1: "Configure-Request",
349                 2: "Configure-Ack",
350                 3: "Configure-Nak",
351                 4: "Configure-Reject",
352                 5: "Terminate-Request",
353                 6: "Terminate-Ack",
354                 7: "Code-Reject",
355                 8: "Protocol-Reject",
356                 9: "Echo-Request",
357                10: "Echo-Reply",
358                11: "Discard-Request"}
359
360
361class PPP_LCP(Packet):
362    name = "PPP Link Control Protocol"
363    fields_desc = [ByteEnumField("code", 5, _PPP_lcptypes),
364                   XByteField("id", 0),
365                   FieldLenField("len", None, fmt="H", length_of="data",
366                                 adjust=lambda p, x: x + 4),
367                   StrLenField("data", "",
368                               length_from=lambda p:p.len-4)]
369
370    def mysummary(self):
371        return self.sprintf('LCP %code%')
372
373    def extract_padding(self, pay):
374        return b"", pay
375
376    @classmethod
377    def dispatch_hook(cls, _pkt = None, *args, **kargs):
378        if _pkt:
379            o = orb(_pkt[0])
380            if o in [1, 2, 3, 4]:
381                return PPP_LCP_Configure
382            elif o in [5,6]:
383                return PPP_LCP_Terminate
384            elif o == 7:
385                return PPP_LCP_Code_Reject
386            elif o == 8:
387                return PPP_LCP_Protocol_Reject
388            elif o in [9, 10]:
389                return PPP_LCP_Echo
390            elif o == 11:
391                return PPP_LCP_Discard_Request
392            else:
393                return cls
394        return cls
395
396
397_PPP_lcp_optiontypes = {1: "Maximum-Receive-Unit",
398                        2: "Async-Control-Character-Map",
399                        3: "Authentication-protocol",
400                        4: "Quality-protocol",
401                        5: "Magic-number",
402                        7: "Protocol-Field-Compression",
403                        8: "Address-and-Control-Field-Compression",
404                        13: "Callback"}
405
406
407class PPP_LCP_Option(Packet):
408    name = "PPP LCP Option"
409    fields_desc = [ByteEnumField("type", None, _PPP_lcp_optiontypes),
410                   FieldLenField("len", None, fmt="B", length_of="data",
411                                 adjust=lambda p,x:x+2),
412                   StrLenField("data", None, length_from=lambda p:p.len-2)]
413
414    def extract_padding(self, pay):
415        return b"", pay
416
417    registered_options = {}
418
419    @classmethod
420    def register_variant(cls):
421        cls.registered_options[cls.type.default] = cls
422
423    @classmethod
424    def dispatch_hook(cls, _pkt=None, *args, **kargs):
425        if _pkt:
426            o = orb(_pkt[0])
427            return cls.registered_options.get(o, cls)
428        return cls
429
430
431class PPP_LCP_MRU_Option(PPP_LCP_Option):
432    fields_desc = [ByteEnumField("type", 1, _PPP_lcp_optiontypes),
433                   FieldLenField("len", 4, fmt="B", adjust=lambda p,x:4),
434                   ShortField("max_recv_unit", 1500)]
435
436_PPP_LCP_auth_protocols = {0xc023: "Password authentication protocol",
437                           0xc223: "Challenge-response authentication protocol",
438                           0xc227: "PPP Extensible authentication protocol"}
439
440_PPP_LCP_CHAP_algorithms = {5: "MD5",
441                            6: "SHA1",
442                            128: "MS-CHAP",
443                            129: "MS-CHAP-v2"}
444
445
446class PPP_LCP_ACCM_Option(PPP_LCP_Option):
447    fields_desc = [ByteEnumField("type", 2, _PPP_lcp_optiontypes),
448                   FieldLenField("len", 6, fmt="B"),
449                   BitField("accm", 0x00000000, 32)]
450
451
452def adjust_auth_len(pkt, x):
453    if pkt.auth_protocol == 0xc223:
454        return 5
455    elif pkt.auth_protocol == 0xc023:
456        return 4
457    else:
458        return x + 4
459
460
461class PPP_LCP_Auth_Protocol_Option(PPP_LCP_Option):
462    fields_desc = [ByteEnumField("type", 3, _PPP_lcp_optiontypes),
463                   FieldLenField("len", None, fmt="B", length_of="data",
464                                 adjust=adjust_auth_len),
465                   ShortEnumField("auth_protocol", 0xc023, _PPP_LCP_auth_protocols),
466                   ConditionalField(StrLenField("data", '', length_from=lambda p:p.len-4),
467                                    lambda p:p.auth_protocol != 0xc223),
468                   ConditionalField(ByteEnumField("algorithm", 5, _PPP_LCP_CHAP_algorithms),
469                                    lambda p:p.auth_protocol == 0xc223)]
470
471
472_PPP_LCP_quality_protocols = {0xc025: "Link Quality Report"}
473
474
475class PPP_LCP_Quality_Protocol_Option(PPP_LCP_Option):
476    fields_desc = [ByteEnumField("type", 4, _PPP_lcp_optiontypes),
477                   FieldLenField("len", None, fmt="B", length_of="data",
478                                 adjust=lambda p,x:x+4),
479                   ShortEnumField("quality_protocol", 0xc025, _PPP_LCP_quality_protocols),
480                   StrLenField("data", "", length_from=lambda p:p.len-4)]
481
482
483class PPP_LCP_Magic_Number_Option(PPP_LCP_Option):
484    fields_desc = [ByteEnumField("type", 5, _PPP_lcp_optiontypes),
485                   FieldLenField("len", 6, fmt="B", adjust = lambda p,x:6),
486                   IntField("magic_number", None)]
487
488
489_PPP_lcp_callback_operations = {0: "Location determined by user authentication",
490                                1: "Dialing string",
491                                2: "Location identifier",
492                                3: "E.164 number",
493                                4: "Distinguished name"}
494
495
496class PPP_LCP_Callback_Option(PPP_LCP_Option):
497    fields_desc = [ByteEnumField("type", 13, _PPP_lcp_optiontypes),
498                   FieldLenField("len", None, fmt="B", length_of="message",
499                                 adjust=lambda p,x:x+3),
500                   ByteEnumField("operation", 0, _PPP_lcp_callback_operations),
501                   StrLenField("message", "", length_from=lambda p:p.len-3)]
502
503
504class PPP_LCP_Configure(PPP_LCP):
505    fields_desc = [ByteEnumField("code", 1, _PPP_lcptypes),
506                   XByteField("id", 0),
507                   FieldLenField("len", None, fmt="H", length_of="options",
508                                 adjust=lambda p,x:x+4),
509                   PacketListField("options", [], PPP_LCP_Option,
510                                   length_from=lambda p:p.len-4)]
511
512    def answers(self, other):
513        return isinstance(other, PPP_LCP_Configure) and self.code in [2, 3, 4]\
514           and other.code == 1 and other.id == self.id
515
516
517class PPP_LCP_Terminate(PPP_LCP):
518
519    def answers(self, other):
520        return isinstance(other, PPP_LCP_Terminate) and self.code == 6\
521           and other.code == 5 and other.id == self.id
522
523
524class PPP_LCP_Code_Reject(PPP_LCP):
525    fields_desc = [ByteEnumField("code", 7, _PPP_lcptypes),
526                   XByteField("id", 0),
527                   FieldLenField("len", None, fmt="H", length_of="rejected_packet",
528                                 adjust=lambda p,x:x+4),
529                   PacketField("rejected_packet", None, PPP_LCP)]
530
531
532class PPP_LCP_Protocol_Reject(PPP_LCP):
533    fields_desc = [ByteEnumField("code", 8, _PPP_lcptypes),
534                   XByteField("id", 0),
535                   FieldLenField("len", None, fmt="H", length_of="rejected_information",
536                                 adjust=lambda p,x:x+6),
537                   ShortEnumField("rejected_protocol", None, _PPP_proto),
538                   PacketField("rejected_information", None, Packet)]
539
540
541class PPP_LCP_Echo(PPP_LCP):
542     fields_desc = [ByteEnumField("code", 9, _PPP_lcptypes),
543                    XByteField("id", 0),
544                    FieldLenField("len", None, fmt="H", length_of="data",
545                                 adjust=lambda p,x:x+8),
546                    IntField("magic_number", None),
547                    StrLenField("data", "", length_from=lambda p:p.len-8)]
548
549     def answers(self, other):
550         return isinstance(other, PPP_LCP_Echo) and self.code == 10\
551            and other.code == 9 and self.id == other.id
552
553
554class PPP_LCP_Discard_Request(PPP_LCP):
555    fields_desc = [ByteEnumField("code", 11, _PPP_lcptypes),
556                   XByteField("id", 0),
557                   FieldLenField("len", None, fmt="H", length_of="data",
558                                 adjust=lambda p,x:x+8),
559                   IntField("magic_number", None),
560                   StrLenField("data", "", length_from=lambda p:p.len-8)]
561
562### Password authentication protocol (RFC 1334)
563
564_PPP_paptypes = {1: "Authenticate-Request",
565                 2: "Authenticate-Ack",
566                 3: "Authenticate-Nak"}
567
568
569class PPP_PAP(Packet):
570    name = "PPP Password Authentication Protocol"
571    fields_desc = [ByteEnumField("code", 1, _PPP_paptypes),
572                   XByteField("id", 0),
573                   FieldLenField("len", None, fmt="!H", length_of="data",
574                                 adjust=lambda _, x: x + 4),
575                   StrLenField("data", "", length_from=lambda p: p.len-4)]
576
577    @classmethod
578    def dispatch_hook(cls, _pkt=None, *_, **kargs):
579        code = None
580        if _pkt:
581            code = orb(_pkt[0])
582        elif "code" in kargs:
583            code = kargs["code"]
584            if isinstance(code, six.string_types):
585                code = cls.fields_desc[0].s2i[code]
586
587        if code == 1:
588            return PPP_PAP_Request
589        elif code in [2, 3]:
590            return PPP_PAP_Response
591        return cls
592
593    def extract_padding(self, pay):
594        return "", pay
595
596
597class PPP_PAP_Request(PPP_PAP):
598    fields_desc = [ByteEnumField("code", 1, _PPP_paptypes),
599                   XByteField("id", 0),
600                   FieldLenField("len", None, fmt="!H", length_of="username",
601                                 adjust=lambda p, x: x + 6 + len(p.password)),
602                   FieldLenField("username_len", None, fmt="B", length_of="username"),
603                   StrLenField("username", None, length_from=lambda p: p.username_len),
604                   FieldLenField("passwd_len", None, fmt="B", length_of="password"),
605                   StrLenField("password", None, length_from=lambda p: p.passwd_len)]
606
607    def mysummary(self):
608        return self.sprintf("PAP-Request username=%PPP_PAP_Request.username%" +
609                            " password=%PPP_PAP_Request.password%")
610
611
612class PPP_PAP_Response(PPP_PAP):
613    fields_desc = [ByteEnumField("code", 2, _PPP_paptypes),
614                   XByteField("id", 0),
615                   FieldLenField("len", None, fmt="!H", length_of="message",
616                                 adjust=lambda _, x: x + 5),
617                   FieldLenField("msg_len", None, fmt="B", length_of="message"),
618                   StrLenField("message", "", length_from=lambda p: p.msg_len)]
619
620    def answers(self, other):
621        return isinstance(other, PPP_PAP_Request) and other.id == self.id
622
623    def mysummary(self):
624        res = "PAP-Ack" if self.code == 2 else "PAP-Nak"
625        if self.msg_len > 0:
626            res += self.sprintf(" msg=%PPP_PAP_Response.message%")
627        return res
628
629
630### Challenge Handshake Authentication protocol (RFC1994)
631
632_PPP_chaptypes = {1: "Challenge",
633                  2: "Response",
634                  3: "Success",
635                  4: "Failure"}
636
637
638class PPP_CHAP(Packet):
639    name = "PPP Challenge Handshake Authentication Protocol"
640    fields_desc = [ByteEnumField("code", 1, _PPP_chaptypes),
641                   XByteField("id", 0),
642                   FieldLenField("len", None, fmt="!H", length_of="data",
643                                 adjust=lambda _, x: x + 4),
644                   StrLenField("data", "", length_from=lambda p: p.len - 4)]
645
646    def answers(self, other):
647        return isinstance(other, PPP_CHAP_ChallengeResponse) and other.code == 2\
648               and self.code in (3, 4) and self.id == other.id
649
650    @classmethod
651    def dispatch_hook(cls, _pkt=None, *_, **kargs):
652        code = None
653        if _pkt:
654            code = orb(_pkt[0])
655        elif "code" in kargs:
656            code = kargs["code"]
657            if isinstance(code, six.string_types):
658                code = cls.fields_desc[0].s2i[code]
659
660        if code in (1, 2):
661            return PPP_CHAP_ChallengeResponse
662        return cls
663
664    def extract_padding(self, pay):
665        return "", pay
666
667    def mysummary(self):
668        if self.code == 3:
669            return self.sprintf("CHAP Success message=%PPP_CHAP.data%")
670        elif self.code == 4:
671            return self.sprintf("CHAP Failure message=%PPP_CHAP.data%")
672
673
674class PPP_CHAP_ChallengeResponse(PPP_CHAP):
675    fields_desc = [ByteEnumField("code", 1, _PPP_chaptypes),
676                   XByteField("id", 0),
677                   FieldLenField("len", None, fmt="!H", length_of="value",
678                                 adjust=lambda p, x: x + len(p.optional_name) + 5),
679                   FieldLenField("value_size", None, fmt="B", length_of="value"),
680                   XStrLenField("value", b"\0"*8, length_from=lambda p: p.value_size),
681                   StrLenField("optional_name", "", length_from=lambda p: p.len - p.value_size - 5)]
682
683    def answers(self, other):
684        return isinstance(other, PPP_CHAP_ChallengeResponse) and other.code == 1\
685               and self.code == 2 and self.id == other.id
686
687    def mysummary(self):
688        if self.code == 1:
689            return self.sprintf("CHAP challenge=0x%PPP_CHAP_ChallengeResponse.value% " +
690                                "optional_name=%PPP_CHAP_ChallengeResponse.optional_name%")
691        elif self.code == 2:
692            return self.sprintf("CHAP response=0x%PPP_CHAP_ChallengeResponse.value% " +
693                                "optional_name=%PPP_CHAP_ChallengeResponse.optional_name%")
694        else:
695            return PPP_CHAP.mysummary(self)
696
697
698bind_layers( Ether,         PPPoED,        type=0x8863)
699bind_layers( Ether,         PPPoE,         type=0x8864)
700bind_layers( CookedLinux,   PPPoED,        proto=0x8863)
701bind_layers( CookedLinux,   PPPoE,         proto=0x8864)
702bind_layers( PPPoE,         PPP,           code=0)
703bind_layers( HDLC,          PPP,           )
704bind_layers( PPP,           EAP,           proto=0xc227)
705bind_layers( PPP,           IP,            proto=0x0021)
706bind_layers( PPP,           IPv6,          proto=0x0057)
707bind_layers( PPP,           PPP_CHAP,      proto=0xc223)
708bind_layers( PPP,           PPP_IPCP,      proto=0x8021)
709bind_layers( PPP,           PPP_ECP,       proto=0x8053)
710bind_layers( PPP,           PPP_LCP,       proto=0xc021)
711bind_layers( PPP,           PPP_PAP,       proto=0xc023)
712bind_layers( Ether,         PPP_IPCP,      type=0x8021)
713bind_layers( Ether,         PPP_ECP,       type=0x8053)
714bind_layers( GRE_PPTP,      PPP,           proto=0x880b)
715
716
717conf.l2types.register(DLT_PPP, PPP)
718conf.l2types.register(DLT_PPP_SERIAL, HDLC)
719conf.l2types.register(DLT_PPP_ETHER, PPPoE)
720