blob: 6ec17c5b05bef22dab7895fb11fac397ecb97cf4 [file] [log] [blame]
## This file is part of Scapy
## See http://www.secdev.org/projects/scapy for more informations
## Copyright (C) Jan Sebechlebsky <sebechlebskyjan@gmail.com>
## This program is published under a GPLv2 license
"""
PPTP (Point to Point Tunneling Protocol)
[RFC 2637]
"""
from scapy.packet import Packet, bind_layers
from scapy.layers.inet import TCP
from scapy.compat import *
from scapy.fields import ByteEnumField, FieldLenField, FlagsField, IntField, IntEnumField,\
LenField, XIntField, ShortField, ShortEnumField, StrFixedLenField,\
StrLenField, XShortField, XByteField
_PPTP_MAGIC_COOKIE = 0x1a2b3c4d
_PPTP_msg_type = {1: "Control Message",
2: "Managemenent Message"}
_PPTP_ctrl_msg_type = { # Control Connection Management
1: "Start-Control-Connection-Request",
2: "Start-Control-Connection-Reply",
3: "Stop-Control-Connection-Request",
4: "Stop-Control-Connection-Reply",
5: "Echo-Request",
6: "Echo-Reply",
# Call Management
7: "Outgoing-Call-Request",
8: "Outgoing-Call-Reply",
9: "Incoming-Call-Request",
10: "Incoming-Call-Reply",
11: "Incoming-Call-Connected",
12: "Call-Clear-Request",
13: "Call-Disconnect-Notify",
# Error Reporting
14: "WAN-Error-Notify",
# PPP Session Control
15: "Set-Link-Info"}
_PPTP_general_error_code = {0: "None",
1: "Not-Connected",
2: "Bad-Format",
3: "Bad-Value",
4: "No-Resource",
5: "Bad-Call ID",
6: "PAC-Error"}
class PPTP(Packet):
name = "PPTP"
fields_desc = [FieldLenField("len", None, fmt="H", length_of="data",
adjust=lambda p, x: x + 12),
ShortEnumField("type", 1, _PPTP_msg_type),
XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
ShortEnumField("ctrl_msg_type", 1, _PPTP_ctrl_msg_type),
XShortField("reserved_0", 0x0000),
StrLenField("data", "",length_from=lambda p: p.len - 12)]
registered_options = {}
@classmethod
def register_variant(cls):
cls.registered_options[cls.ctrl_msg_type.default] = cls
@classmethod
def dispatch_hook(cls, _pkt=None, *args, **kargs):
if _pkt:
o = orb(_pkt[9])
return cls.registered_options.get(o, cls)
return cls
_PPTP_FRAMING_CAPABILITIES_FLAGS = ["Asynchronous Framing supported",
"Synchronous Framing supported"]
_PPTP_BEARER_CAPABILITIES_FLAGS = ["Analog access supported",
"Digital access supported"]
class PPTPStartControlConnectionRequest(PPTP):
name = "PPTP Start Control Connection Request"
fields_desc = [LenField("len", 156),
ShortEnumField("type", 1, _PPTP_msg_type),
XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
ShortEnumField("ctrl_msg_type", 1, _PPTP_ctrl_msg_type),
XShortField("reserved_0", 0x0000),
ShortField("protocol_version", 1),
XShortField("reserved_1", 0x0000),
FlagsField("framing_capabilities", 0, 32,
_PPTP_FRAMING_CAPABILITIES_FLAGS),
FlagsField("bearer_capabilities", 0, 32,
_PPTP_BEARER_CAPABILITIES_FLAGS),
ShortField("maximum_channels", 65535),
ShortField("firmware_revision", 256),
StrFixedLenField("host_name", "linux", 64),
StrFixedLenField("vendor_string", "", 64)]
_PPTP_start_control_connection_result = {1: "OK",
2: "General error",
3: "Command channel already exists",
4: "Not authorized",
5: "Unsupported protocol version"}
class PPTPStartControlConnectionReply(PPTP):
name = "PPTP Start Control Connection Reply"
fields_desc = [LenField("len", 156),
ShortEnumField("type", 1, _PPTP_msg_type),
XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
ShortEnumField("ctrl_msg_type", 2, _PPTP_ctrl_msg_type),
XShortField("reserved_0", 0x0000),
ShortField("protocol_version", 1),
ByteEnumField("result_code", 1,
_PPTP_start_control_connection_result),
ByteEnumField("error_code", 0, _PPTP_general_error_code),
FlagsField("framing_capabilities", 0, 32,
_PPTP_FRAMING_CAPABILITIES_FLAGS),
FlagsField("bearer_capabilities", 0, 32,
_PPTP_BEARER_CAPABILITIES_FLAGS),
ShortField("maximum_channels", 65535),
ShortField("firmware_revision", 256),
StrFixedLenField("host_name", "linux", 64),
StrFixedLenField("vendor_string", "", 64)]
def answers(self, other):
return isinstance(other, PPTPStartControlConnectionRequest)
_PPTP_stop_control_connection_reason = {1: "None",
2: "Stop-Protocol",
3: "Stop-Local-Shutdown"}
class PPTPStopControlConnectionRequest(PPTP):
name = "PPTP Stop Control Connection Request"
fields_desc = [LenField("len", 16),
ShortEnumField("type", 1, _PPTP_msg_type),
XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
ShortEnumField("ctrl_msg_type", 3, _PPTP_ctrl_msg_type),
XShortField("reserved_0", 0x0000),
ByteEnumField("reason", 1,
_PPTP_stop_control_connection_reason),
XByteField("reserved_1", 0x00),
XShortField("reserved_2", 0x0000)]
_PPTP_stop_control_connection_result = {1: "OK",
2: "General error"}
class PPTPStopControlConnectionReply(PPTP):
name = "PPTP Stop Control Connection Reply"
fields_desc = [LenField("len", 16),
ShortEnumField("type", 1, _PPTP_msg_type),
XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
ShortEnumField("ctrl_msg_type", 4, _PPTP_ctrl_msg_type),
XShortField("reserved_0", 0x0000),
ByteEnumField("result_code", 1,
_PPTP_stop_control_connection_result),
ByteEnumField("error_code", 0, _PPTP_general_error_code),
XShortField("reserved_2", 0x0000)]
def answers(self, other):
return isinstance(other, PPTPStopControlConnectionRequest)
class PPTPEchoRequest(PPTP):
name = "PPTP Echo Request"
fields_desc = [LenField("len", 16),
ShortEnumField("type", 1, _PPTP_msg_type),
XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
ShortEnumField("ctrl_msg_type", 5, _PPTP_ctrl_msg_type),
XShortField("reserved_0", 0x0000),
IntField("identifier", None)]
_PPTP_echo_result = {1: "OK",
2: "General error"}
class PPTPEchoReply(PPTP):
name = "PPTP Echo Reply"
fields_desc = [LenField("len", 20),
ShortEnumField("type", 1, _PPTP_msg_type),
XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
ShortEnumField("ctrl_msg_type", 6, _PPTP_ctrl_msg_type),
XShortField("reserved_0", 0x0000),
IntField("identifier", None),
ByteEnumField("result_code", 1, _PPTP_echo_result),
ByteEnumField("error_code", 0, _PPTP_general_error_code),
XShortField("reserved_1", 0x0000)]
def answers(self, other):
return isinstance(other, PPTPEchoRequest) and other.identifier == self.identifier
_PPTP_bearer_type = {1: "Analog channel",
2: "Digital channel",
3: "Any type of channel"}
_PPTP_framing_type = {1: "Asynchronous framing",
2: "Synchronous framing",
3: "Any type of framing"}
class PPTPOutgoingCallRequest(PPTP):
name = "PPTP Outgoing Call Request"
fields_desc = [LenField("len", 168),
ShortEnumField("type", 1, _PPTP_msg_type),
XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
ShortEnumField("ctrl_msg_type", 7, _PPTP_ctrl_msg_type),
XShortField("reserved_0", 0x0000),
ShortField("call_id", 1),
ShortField("call_serial_number", 0),
IntField("minimum_bps", 32768),
IntField("maximum_bps", 2147483648),
IntEnumField("bearer_type", 3, _PPTP_bearer_type),
IntEnumField("framing_type", 3, _PPTP_framing_type),
ShortField("pkt_window_size", 16),
ShortField("pkt_proc_delay", 0),
ShortField('phone_number_len', 0),
XShortField("reserved_1", 0x0000),
StrFixedLenField("phone_number", '', 64),
StrFixedLenField("subaddress", '', 64)]
_PPTP_result_code = {1: "Connected",
2: "General error",
3: "No Carrier",
4: "Busy",
5: "No dial tone",
6: "Time-out",
7: "Do not accept"}
class PPTPOutgoingCallReply(PPTP):
name = "PPTP Outgoing Call Reply"
fields_desc = [LenField("len", 32),
ShortEnumField("type", 1, _PPTP_msg_type),
XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
ShortEnumField("ctrl_msg_type", 8, _PPTP_ctrl_msg_type),
XShortField("reserved_0", 0x0000),
ShortField("call_id", 1),
ShortField("peer_call_id", 1),
ByteEnumField("result_code", 1, _PPTP_result_code),
ByteEnumField("error_code", 0, _PPTP_general_error_code),
ShortField("cause_code", 0),
IntField("connect_speed", 100000000),
ShortField("pkt_window_size", 16),
ShortField("pkt_proc_delay", 0),
IntField("channel_id", 0)]
def answers(self, other):
return isinstance(other, PPTPOutgoingCallRequest) and other.call_id == self.peer_call_id
class PPTPIncomingCallRequest(PPTP):
name = "PPTP Incoming Call Request"
fields_desc = [LenField("len", 220),
ShortEnumField("type", 1, _PPTP_msg_type),
XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
ShortEnumField("ctrl_msg_type", 9, _PPTP_ctrl_msg_type),
XShortField("reserved_0", 0x0000),
ShortField("call_id", 1),
ShortField("call_serial_number", 1),
IntEnumField("bearer_type", 3, _PPTP_bearer_type),
IntField("channel_id", 0),
ShortField("dialed_number_len", 0),
ShortField("dialing_number_len", 0),
StrFixedLenField("dialed_number", "", 64),
StrFixedLenField("dialing_number", "", 64),
StrFixedLenField("subaddress", "", 64)]
class PPTPIncomingCallReply(PPTP):
name = "PPTP Incoming Call Reply"
fields_desc = [LenField("len", 148),
ShortEnumField("type", 1, _PPTP_msg_type),
XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
ShortEnumField("ctrl_msg_type", 10, _PPTP_ctrl_msg_type),
XShortField("reserved_0", 0x0000),
ShortField("call_id", 1),
ShortField("peer_call_id", 1),
ByteEnumField("result_code", 1, _PPTP_result_code),
ByteEnumField("error_code", 0, _PPTP_general_error_code),
ShortField("pkt_window_size", 64),
ShortField("pkt_transmit_delay", 0),
XShortField("reserved_1", 0x0000)]
def answers(self, other):
return isinstance(other, PPTPIncomingCallRequest) and other.call_id == self.peer_call_id
class PPTPIncomingCallConnected(PPTP):
name = "PPTP Incoming Call Connected"
fields_desc = [LenField("len", 28),
ShortEnumField("type", 1, _PPTP_msg_type),
XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
ShortEnumField("ctrl_msg_type", 11, _PPTP_ctrl_msg_type),
XShortField("reserved_0", 0x0000),
ShortField("peer_call_id", 1),
XShortField("reserved_1", 0x0000),
IntField("connect_speed", 100000000),
ShortField("pkt_window_size", 64),
ShortField("pkt_transmit_delay", 0),
IntEnumField("framing_type", 1, _PPTP_framing_type)]
def answers(self, other):
return isinstance(other, PPTPIncomingCallReply) and other.call_id == self.peer_call_id
class PPTPCallClearRequest(PPTP):
name = "PPTP Call Clear Request"
fields_desc = [LenField("len", 16),
ShortEnumField("type", 1, _PPTP_msg_type),
XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
ShortEnumField("ctrl_msg_type", 12, _PPTP_ctrl_msg_type),
XShortField("reserved_0", 0x0000),
ShortField("call_id", 1),
XShortField("reserved_1", 0x0000)]
_PPTP_call_disconnect_result = {1: "Lost Carrier",
2: "General error",
3: "Admin Shutdown",
4: "Request"}
class PPTPCallDisconnectNotify(PPTP):
name = "PPTP Call Disconnect Notify"
fields_desc = [LenField("len", 148),
ShortEnumField("type", 1, _PPTP_msg_type),
XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
ShortEnumField("ctrl_msg_type", 13, _PPTP_ctrl_msg_type),
XShortField("reserved_0", 0x0000),
ShortField("call_id", 1),
ByteEnumField("result_code", 1,
_PPTP_call_disconnect_result),
ByteEnumField("error_code", 0, _PPTP_general_error_code),
ShortField("cause_code", 0),
XShortField("reserved_1", 0x0000),
StrFixedLenField("call_statistic", "", 128)]
class PPTPWANErrorNotify(PPTP):
name = "PPTP WAN Error Notify"
fields_desc = [LenField("len", 40),
ShortEnumField("type", 1, _PPTP_msg_type),
XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
ShortEnumField("ctrl_msg_type", 14, _PPTP_ctrl_msg_type),
XShortField("reserved_0", 0x0000),
ShortField("peer_call_id", 1),
XShortField("reserved_1", 0x0000),
IntField("crc_errors", 0),
IntField("framing_errors", 0),
IntField("hardware_overruns", 0),
IntField("buffer_overruns", 0),
IntField("time_out_errors", 0),
IntField("alignment_errors", 0)]
class PPTPSetLinkInfo(PPTP):
name = "PPTP Set Link Info"
fields_desc = [LenField("len", 24),
ShortEnumField("type", 1, _PPTP_msg_type),
XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
ShortEnumField("ctrl_msg_type", 15, _PPTP_ctrl_msg_type),
XShortField("reserved_0", 0x0000),
ShortField("peer_call_id", 1),
XShortField("reserved_1", 0x0000),
XIntField("send_accm", 0x00000000),
XIntField("receive_accm", 0x00000000)]
bind_layers(TCP, PPTP, sport=1723)
bind_layers(TCP, PPTP, dport=1723)