diff --git a/scapy/layers/ppp.py b/scapy/layers/ppp.py index 19d320857ab1defe4e9c6fb01e1746ed88df9307..ec5357c1179368828d24faa8452d620e3c831746 100644 --- a/scapy/layers/ppp.py +++ b/scapy/layers/ppp.py @@ -17,7 +17,7 @@ from scapy.layers.inet6 import IPv6 from scapy.fields import BitField, ByteEnumField, ByteField, \ ConditionalField, FieldLenField, IntField, IPField, LenField, \ PacketListField, PacketField, ShortEnumField, ShortField, \ - StrFixedLenField, StrLenField, XByteField, XShortField + StrFixedLenField, StrLenField, XByteField, XShortField, XStrLenField class PPPoE(Packet): @@ -620,6 +620,74 @@ class PPP_PAP_Response(PPP_PAP): return res +### Challenge Handshake Authentication protocol (RFC1994) + +_PPP_chaptypes = {1: "Challenge", + 2: "Response", + 3: "Success", + 4: "Failure"} + + +class PPP_CHAP(Packet): + name = "PPP Challenge Handshake Authentication Protocol" + fields_desc = [ByteEnumField("code", 1, _PPP_chaptypes), + XByteField("id", 0), + FieldLenField("len", None, fmt="!H", length_of="data", + adjust=lambda _, x: x + 4), + StrLenField("data", "", length_from=lambda p: p.len - 4)] + + def answers(self, other): + return isinstance(other, PPP_CHAP_ChallengeResponse) and other.code == 2\ + and self.code in (3, 4) and self.id == other.id + + @classmethod + def dispatch_hook(cls, _pkt=None, *_, **kargs): + code = None + if _pkt: + code = ord(_pkt[0]) + elif "code" in kargs: + code = kargs["code"] + if isinstance(code, basestring): + code = cls.fields_desc[0].s2i[code] + + if code in (1, 2): + return PPP_CHAP_ChallengeResponse + return cls + + def extract_padding(self, pay): + return "", pay + + def mysummary(self): + if self.code == 3: + return self.sprintf("CHAP Success message=%PPP_CHAP.data%") + elif self.code == 4: + return self.sprintf("CHAP Failure message=%PPP_CHAP.data%") + + +class PPP_CHAP_ChallengeResponse(PPP_CHAP): + fields_desc = [ByteEnumField("code", 1, _PPP_chaptypes), + XByteField("id", 0), + FieldLenField("len", None, fmt="!H", length_of="value", + adjust=lambda p, x: x + len(p.optional_name) + 5), + FieldLenField("value_size", None, fmt="B", length_of="value"), + XStrLenField("value", b"\0"*8, length_from=lambda p: p.value_size), + StrLenField("optional_name", "", length_from=lambda p: p.len - p.value_size - 5)] + + def answers(self, other): + return isinstance(other, PPP_CHAP_ChallengeResponse) and other.code == 1\ + and self.code == 2 and self.id == other.id + + def mysummary(self): + if self.code == 1: + return self.sprintf("CHAP challenge=0x%PPP_CHAP_ChallengeResponse.value% " + + "optional_name=%PPP_CHAP_ChallengeResponse.optional_name%") + elif self.code == 2: + return self.sprintf("CHAP response=0x%PPP_CHAP_ChallengeResponse.value% " + + "optional_name=%PPP_CHAP_ChallengeResponse.optional_name%") + else: + return PPP_CHAP.mysummary(self) + + bind_layers( Ether, PPPoED, type=0x8863) bind_layers( Ether, PPPoE, type=0x8864) bind_layers( CookedLinux, PPPoED, proto=0x8863) @@ -629,6 +697,7 @@ bind_layers( HDLC, PPP, ) bind_layers( PPP, EAP, proto=0xc227) bind_layers( PPP, IP, proto=0x0021) bind_layers( PPP, IPv6, proto=0x0057) +bind_layers( PPP, PPP_CHAP, proto=0xc223) bind_layers( PPP, PPP_IPCP, proto=0x8021) bind_layers( PPP, PPP_ECP, proto=0x8053) bind_layers( PPP, PPP_LCP, proto=0xc021)