Skip to content
Snippets Groups Projects
Commit d79c849e authored by Jan Sebechlebsky's avatar Jan Sebechlebsky
Browse files

Add support for PPP Link Control Protocol

parent d95249d0
No related branches found
No related tags found
No related merge requests found
...@@ -11,13 +11,13 @@ PPP (Point to Point Protocol) ...@@ -11,13 +11,13 @@ PPP (Point to Point Protocol)
import struct import struct
from scapy.packet import Packet, bind_layers from scapy.packet import Packet, bind_layers
from scapy.layers.l2 import Ether, CookedLinux from scapy.layers.l2 import Ether, CookedLinux, GRE_PPTP
from scapy.layers.inet import IP from scapy.layers.inet import IP
from scapy.layers.inet6 import IPv6 from scapy.layers.inet6 import IPv6
from scapy.fields import BitField, ByteEnumField, ByteField, \ from scapy.fields import BitField, ByteEnumField, ByteField, \
ConditionalField, FieldLenField, IPField, PacketListField, \ ConditionalField, FieldLenField, IntField, IPField, LenField, \
ShortEnumField, ShortField, StrFixedLenField, StrLenField, XByteField, \ PacketListField, PacketField, ShortEnumField, ShortField, \
XShortField StrFixedLenField, StrLenField, XByteField, XShortField
class PPPoE(Packet): class PPPoE(Packet):
...@@ -339,6 +339,220 @@ class PPP_ECP(Packet): ...@@ -339,6 +339,220 @@ class PPP_ECP(Packet):
FieldLenField("len" , None, fmt="H", length_of="options", adjust=lambda p,x:x+4 ), FieldLenField("len" , None, fmt="H", length_of="options", adjust=lambda p,x:x+4 ),
PacketListField("options", [], PPP_ECP_Option, length_from=lambda p:p.len-4,) ] PacketListField("options", [], PPP_ECP_Option, length_from=lambda p:p.len-4,) ]
### Link Control Protocol (RFC 1661)
_PPP_lcptypes = {1: "Configure-Request",
2: "Configure-Ack",
3: "Configure-Nak",
4: "Configure-Reject",
5: "Terminate-Request",
6: "Terminate-Ack",
7: "Code-Reject",
8: "Protocol-Reject",
9: "Echo-Request",
10: "Echo-Reply",
11: "Discard-Request"}
class PPP_LCP(Packet):
name = "PPP Link Control Protocol"
fields_desc = [ByteEnumField("code", 5, _PPP_lcptypes),
XByteField("id", 0),
FieldLenField("len", None, fmt="H", length_of="data",
adjust=lambda p, x: x + 4),
StrLenField("data", "",
length_from=lambda p:p.len-4)]
def extract_padding(self, pay):
return "",pay
@classmethod
def dispatch_hook(cls, _pkt = None, *args, **kargs):
if _pkt:
o = ord(_pkt[0])
if o in [1, 2, 3, 4]:
return PPP_LCP_Configure
elif o in [5,6]:
return PPP_LCP_Terminate
elif o == 7:
return PPP_LCP_Code_Reject
elif o == 8:
return PPP_LCP_Protocol_Reject
elif o in [9, 10]:
return PPP_LCP_Echo
elif o == 11:
return PPP_LCP_Discard_Request
else:
return cls
return cls
_PPP_lcp_optiontypes = {1: "Maximum-Receive-Unit",
2: "Async-Control-Character-Map",
3: "Authentication-protocol",
4: "Quality-protocol",
5: "Magic-number",
7: "Protocol-Field-Compression",
8: "Address-and-Control-Field-Compression",
13: "Callback"}
class PPP_LCP_Option(Packet):
name = "PPP LCP Option"
fields_desc = [ByteEnumField("type", None, _PPP_lcp_optiontypes),
FieldLenField("len", None, fmt="B", length_of="data",
adjust=lambda p,x:x+2),
StrLenField("data", None, length_from=lambda p:p.len-2)]
def extract_padding(self, pay):
return "", pay
registered_options = {}
@classmethod
def register_variant(cls):
cls.registered_options[cls.type.default] = cls
@classmethod
def dispatch_hook(cls, _pkt=None, *args, **kargs):
if _pkt:
o = ord(_pkt[0])
return cls.registered_options.get(o, cls)
return cls
class PPP_LCP_MRU_Option(PPP_LCP_Option):
fields_desc = [ByteEnumField("type", 1, _PPP_lcp_optiontypes),
FieldLenField("len", 4, fmt="B", adjust=lambda p,x:4),
ShortField("max_recv_unit", 1500)]
_PPP_LCP_auth_protocols = {0xc023: "Password authentication protocol",
0xc223: "Challenge-response authentication protocol",
0xc227: "PPP Extensible authentication protocol"}
_PPP_LCP_CHAP_algorithms = {5: "MD5",
6: "SHA1",
128: "MS-CHAP",
129: "MS-CHAP-v2"}
class PPP_LCP_ACCM_Option(PPP_LCP_Option):
fields_desc = [ByteEnumField("type", 2, _PPP_lcp_optiontypes),
FieldLenField("len", 6, fmt="B"),
BitField("accm", 0x00000000, 32)]
def adjust_auth_len(pkt, x):
if pkt.auth_protocol == 0xc223:
return 5
elif pkt.auth_protocol == 0xc023:
return 4
else:
return x + 4
class PPP_LCP_Auth_Protocol_Option(PPP_LCP_Option):
fields_desc = [ByteEnumField("type", 3, _PPP_lcp_optiontypes),
FieldLenField("len", None, fmt="B", length_of="data",
adjust=adjust_auth_len),
ShortEnumField("auth_protocol", 0xc023, _PPP_LCP_auth_protocols),
ConditionalField(StrLenField("data", '', length_from=lambda p:p.len-4),
lambda p:p.auth_protocol != 0xc223),
ConditionalField(ByteEnumField("algorithm", 5, _PPP_LCP_CHAP_algorithms),
lambda p:p.auth_protocol == 0xc223)]
_PPP_LCP_quality_protocols = {0xc025: "Link Quality Report"}
class PPP_LCP_Quality_Protocol_Option(PPP_LCP_Option):
fields_desc = [ByteEnumField("type", 4, _PPP_lcp_optiontypes),
FieldLenField("len", None, fmt="B", length_of="data",
adjust=lambda p,x:x+4),
ShortEnumField("quality_protocol", 0xc025, _PPP_LCP_quality_protocols),
StrLenField("data", "", length_from=lambda p:p.len-4)]
class PPP_LCP_Magic_Number_Option(PPP_LCP_Option):
fields_desc = [ByteEnumField("type", 5, _PPP_lcp_optiontypes),
FieldLenField("len", 6, fmt="B", adjust = lambda p,x:6),
IntField("magic_number", None)]
_PPP_lcp_callback_operations = {0: "Location determined by user authentication",
1: "Dialing string",
2: "Location identifier",
3: "E.164 number",
4: "Distinguished name"}
class PPP_LCP_Callback_Option(PPP_LCP_Option):
fields_desc = [ByteEnumField("type", 13, _PPP_lcp_optiontypes),
FieldLenField("len", None, fmt="B", length_of="message",
adjust=lambda p,x:x+3),
ByteEnumField("operation", 0, _PPP_lcp_callback_operations),
StrLenField("message", "", length_from=lambda p:p.len-3)]
class PPP_LCP_Configure(PPP_LCP):
fields_desc = [ByteEnumField("code", 1, _PPP_lcptypes),
XByteField("id", 0),
FieldLenField("len", None, fmt="H", length_of="options",
adjust=lambda p,x:x+4),
PacketListField("options", [], PPP_LCP_Option,
length_from=lambda p:p.len-4)]
def answers(self, other):
return isinstance(other, PPP_LCP_Configure) and self.code in [2, 3, 4]\
and other.code == 1 and other.id == self.id
class PPP_LCP_Terminate(PPP_LCP):
def answers(self, other):
return isinstance(other, PPP_LCP_Terminate) and self.code == 6\
and other.code == 5 and other.id == self.id
class PPP_LCP_Code_Reject(PPP_LCP):
fields_desc = [ByteEnumField("code", 7, _PPP_lcptypes),
XByteField("id", 0),
FieldLenField("len", None, fmt="H", length_of="rejected_packet",
adjust=lambda p,x:x+4),
PacketField("rejected_packet", None, PPP_LCP)]
class PPP_LCP_Protocol_Reject(PPP_LCP):
fields_desc = [ByteEnumField("code", 8, _PPP_lcptypes),
XByteField("id", 0),
FieldLenField("len", None, fmt="H", length_of="rejected_information",
adjust=lambda p,x:x+6),
ShortEnumField("rejected_protocol", None, _PPP_proto),
PacketField("rejected_information", None, Packet)]
class PPP_LCP_Echo(PPP_LCP):
fields_desc = [ByteEnumField("code", 9, _PPP_lcptypes),
XByteField("id", 0),
FieldLenField("len", None, fmt="H", length_of="data",
adjust=lambda p,x:x+8),
IntField("magic_number", None),
StrLenField("data", "", length_from=lambda p:p.len-8)]
def answers(self, other):
return isinstance(other, PPP_LCP_Echo) and self.code == 10\
and other.code == 9 and self.id == other.id
class PPP_LCP_Discard_Request(PPP_LCP):
fields_desc = [ByteEnumField("code", 11, _PPP_lcptypes),
XByteField("id", 0),
FieldLenField("len", None, fmt="H", length_of="data",
adjust=lambda p,x:x+8),
IntField("magic_number", None),
StrLenField("data", "", length_from=lambda p:p.len-8)]
bind_layers( Ether, PPPoED, type=0x8863) bind_layers( Ether, PPPoED, type=0x8863)
bind_layers( Ether, PPPoE, type=0x8864) bind_layers( Ether, PPPoE, type=0x8864)
bind_layers( CookedLinux, PPPoED, proto=0x8863) bind_layers( CookedLinux, PPPoED, proto=0x8863)
...@@ -349,5 +563,7 @@ bind_layers( PPP, IP, proto=0x0021) ...@@ -349,5 +563,7 @@ bind_layers( PPP, IP, proto=0x0021)
bind_layers( PPP, IPv6, proto=0x0057) bind_layers( PPP, IPv6, proto=0x0057)
bind_layers( PPP, PPP_IPCP, proto=0x8021) bind_layers( PPP, PPP_IPCP, proto=0x8021)
bind_layers( PPP, PPP_ECP, proto=0x8053) bind_layers( PPP, PPP_ECP, proto=0x8053)
bind_layers( PPP, PPP_LCP, proto=0xc021)
bind_layers( Ether, PPP_IPCP, type=0x8021) bind_layers( Ether, PPP_IPCP, type=0x8021)
bind_layers( Ether, PPP_ECP, type=0x8053) bind_layers( Ether, PPP_ECP, type=0x8053)
bind_layers( GRE_PPTP, PPP, proto=0x880b)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment