Home | History | Annotate | Download | only in layers
      1 ## This file is part of Scapy
      2 ## See http://www.secdev.org/projects/scapy for more informations
      3 ## Copyright (C) Jan Sebechlebsky <sebechlebskyjan (at] gmail.com>
      4 ## This program is published under a GPLv2 license
      5 
      6 """
      7 PPTP (Point to Point Tunneling Protocol)
      8 
      9 [RFC 2637]
     10 """
     11 
     12 from scapy.packet import Packet, bind_layers
     13 from scapy.layers.inet import TCP
     14 from scapy.compat import *
     15 from scapy.fields import ByteEnumField, FieldLenField, FlagsField, IntField, IntEnumField,\
     16                          LenField, XIntField, ShortField, ShortEnumField, StrFixedLenField,\
     17                          StrLenField, XShortField, XByteField
     18 
     19 _PPTP_MAGIC_COOKIE = 0x1a2b3c4d
     20 
     21 _PPTP_msg_type = {1: "Control Message",
     22                   2: "Managemenent Message"}
     23 
     24 _PPTP_ctrl_msg_type = {  # Control Connection Management
     25                        1: "Start-Control-Connection-Request",
     26                        2: "Start-Control-Connection-Reply",
     27                        3: "Stop-Control-Connection-Request",
     28                        4: "Stop-Control-Connection-Reply",
     29                        5: "Echo-Request",
     30                        6: "Echo-Reply",
     31                        # Call Management
     32                        7: "Outgoing-Call-Request",
     33                        8: "Outgoing-Call-Reply",
     34                        9: "Incoming-Call-Request",
     35                        10: "Incoming-Call-Reply",
     36                        11: "Incoming-Call-Connected",
     37                        12: "Call-Clear-Request",
     38                        13: "Call-Disconnect-Notify",
     39                        # Error Reporting
     40                        14: "WAN-Error-Notify",
     41                        # PPP Session Control
     42                        15: "Set-Link-Info"}
     43 
     44 _PPTP_general_error_code = {0: "None",
     45                             1: "Not-Connected",
     46                             2: "Bad-Format",
     47                             3: "Bad-Value",
     48                             4: "No-Resource",
     49                             5: "Bad-Call ID",
     50                             6: "PAC-Error"}
     51 
     52 
     53 class PPTP(Packet):
     54     name = "PPTP"
     55     fields_desc = [FieldLenField("len", None, fmt="H", length_of="data",
     56                                  adjust=lambda p, x: x + 12),
     57                    ShortEnumField("type", 1, _PPTP_msg_type),
     58                    XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
     59                    ShortEnumField("ctrl_msg_type", 1, _PPTP_ctrl_msg_type),
     60                    XShortField("reserved_0", 0x0000),
     61                    StrLenField("data", "",length_from=lambda p: p.len - 12)]
     62 
     63     registered_options = {}
     64 
     65     @classmethod
     66     def register_variant(cls):
     67         cls.registered_options[cls.ctrl_msg_type.default] = cls
     68 
     69     @classmethod
     70     def dispatch_hook(cls, _pkt=None, *args, **kargs):
     71         if _pkt:
     72             o = orb(_pkt[9])
     73             return cls.registered_options.get(o, cls)
     74         return cls
     75 
     76 
     77 _PPTP_FRAMING_CAPABILITIES_FLAGS = ["Asynchronous Framing supported",
     78                                     "Synchronous Framing supported"]
     79 
     80 _PPTP_BEARER_CAPABILITIES_FLAGS = ["Analog access supported",
     81                                    "Digital access supported"]
     82 
     83 
     84 class PPTPStartControlConnectionRequest(PPTP):
     85     name = "PPTP Start Control Connection Request"
     86     fields_desc = [LenField("len", 156),
     87                    ShortEnumField("type", 1, _PPTP_msg_type),
     88                    XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
     89                    ShortEnumField("ctrl_msg_type", 1, _PPTP_ctrl_msg_type),
     90                    XShortField("reserved_0", 0x0000),
     91                    ShortField("protocol_version", 1),
     92                    XShortField("reserved_1", 0x0000),
     93                    FlagsField("framing_capabilities", 0, 32,
     94                               _PPTP_FRAMING_CAPABILITIES_FLAGS),
     95                    FlagsField("bearer_capabilities", 0, 32,
     96                               _PPTP_BEARER_CAPABILITIES_FLAGS),
     97                    ShortField("maximum_channels", 65535),
     98                    ShortField("firmware_revision", 256),
     99                    StrFixedLenField("host_name", "linux", 64),
    100                    StrFixedLenField("vendor_string", "", 64)]
    101 
    102 _PPTP_start_control_connection_result = {1: "OK",
    103                                          2: "General error",
    104                                          3: "Command channel already exists",
    105                                          4: "Not authorized",
    106                                          5: "Unsupported protocol version"}
    107 
    108 
    109 class PPTPStartControlConnectionReply(PPTP):
    110     name = "PPTP Start Control Connection Reply"
    111     fields_desc = [LenField("len", 156),
    112                    ShortEnumField("type", 1, _PPTP_msg_type),
    113                    XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
    114                    ShortEnumField("ctrl_msg_type", 2, _PPTP_ctrl_msg_type),
    115                    XShortField("reserved_0", 0x0000),
    116                    ShortField("protocol_version", 1),
    117                    ByteEnumField("result_code", 1,
    118                                  _PPTP_start_control_connection_result),
    119                    ByteEnumField("error_code", 0, _PPTP_general_error_code),
    120                    FlagsField("framing_capabilities", 0, 32,
    121                               _PPTP_FRAMING_CAPABILITIES_FLAGS),
    122                    FlagsField("bearer_capabilities", 0, 32,
    123                               _PPTP_BEARER_CAPABILITIES_FLAGS),
    124                    ShortField("maximum_channels", 65535),
    125                    ShortField("firmware_revision", 256),
    126                    StrFixedLenField("host_name", "linux", 64),
    127                    StrFixedLenField("vendor_string", "", 64)]
    128 
    129     def answers(self, other):
    130         return isinstance(other, PPTPStartControlConnectionRequest)
    131 
    132 
    133 _PPTP_stop_control_connection_reason = {1: "None",
    134                                         2: "Stop-Protocol",
    135                                         3: "Stop-Local-Shutdown"}
    136 
    137 
    138 class PPTPStopControlConnectionRequest(PPTP):
    139     name = "PPTP Stop Control Connection Request"
    140     fields_desc = [LenField("len", 16),
    141                    ShortEnumField("type", 1, _PPTP_msg_type),
    142                    XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
    143                    ShortEnumField("ctrl_msg_type", 3, _PPTP_ctrl_msg_type),
    144                    XShortField("reserved_0", 0x0000),
    145                    ByteEnumField("reason", 1,
    146                                  _PPTP_stop_control_connection_reason),
    147                    XByteField("reserved_1", 0x00),
    148                    XShortField("reserved_2", 0x0000)]
    149 
    150 _PPTP_stop_control_connection_result = {1: "OK",
    151                                         2: "General error"}
    152 
    153 
    154 class PPTPStopControlConnectionReply(PPTP):
    155     name = "PPTP Stop Control Connection Reply"
    156     fields_desc = [LenField("len", 16),
    157                    ShortEnumField("type", 1, _PPTP_msg_type),
    158                    XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
    159                    ShortEnumField("ctrl_msg_type", 4, _PPTP_ctrl_msg_type),
    160                    XShortField("reserved_0", 0x0000),
    161                    ByteEnumField("result_code", 1,
    162                                  _PPTP_stop_control_connection_result),
    163                    ByteEnumField("error_code", 0, _PPTP_general_error_code),
    164                    XShortField("reserved_2", 0x0000)]
    165 
    166     def answers(self, other):
    167         return isinstance(other, PPTPStopControlConnectionRequest)
    168 
    169 
    170 class PPTPEchoRequest(PPTP):
    171     name = "PPTP Echo Request"
    172     fields_desc = [LenField("len", 16),
    173                    ShortEnumField("type", 1, _PPTP_msg_type),
    174                    XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
    175                    ShortEnumField("ctrl_msg_type", 5, _PPTP_ctrl_msg_type),
    176                    XShortField("reserved_0", 0x0000),
    177                    IntField("identifier", None)]
    178 
    179 _PPTP_echo_result = {1: "OK",
    180                      2: "General error"}
    181 
    182 
    183 class PPTPEchoReply(PPTP):
    184     name = "PPTP Echo Reply"
    185     fields_desc = [LenField("len", 20),
    186                    ShortEnumField("type", 1, _PPTP_msg_type),
    187                    XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
    188                    ShortEnumField("ctrl_msg_type", 6, _PPTP_ctrl_msg_type),
    189                    XShortField("reserved_0", 0x0000),
    190                    IntField("identifier", None),
    191                    ByteEnumField("result_code", 1, _PPTP_echo_result),
    192                    ByteEnumField("error_code", 0, _PPTP_general_error_code),
    193                    XShortField("reserved_1", 0x0000)]
    194 
    195     def answers(self, other):
    196         return isinstance(other, PPTPEchoRequest) and other.identifier == self.identifier
    197 
    198 _PPTP_bearer_type = {1: "Analog channel",
    199                      2: "Digital channel",
    200                      3: "Any type of channel"}
    201 
    202 _PPTP_framing_type = {1: "Asynchronous framing",
    203                       2: "Synchronous framing",
    204                       3: "Any type of framing"}
    205 
    206 
    207 class PPTPOutgoingCallRequest(PPTP):
    208     name = "PPTP Outgoing Call Request"
    209     fields_desc = [LenField("len", 168),
    210                    ShortEnumField("type", 1, _PPTP_msg_type),
    211                    XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
    212                    ShortEnumField("ctrl_msg_type", 7, _PPTP_ctrl_msg_type),
    213                    XShortField("reserved_0", 0x0000),
    214                    ShortField("call_id", 1),
    215                    ShortField("call_serial_number", 0),
    216                    IntField("minimum_bps", 32768),
    217                    IntField("maximum_bps", 2147483648),
    218                    IntEnumField("bearer_type", 3, _PPTP_bearer_type),
    219                    IntEnumField("framing_type", 3, _PPTP_framing_type),
    220                    ShortField("pkt_window_size", 16),
    221                    ShortField("pkt_proc_delay", 0),
    222                    ShortField('phone_number_len', 0),
    223                    XShortField("reserved_1", 0x0000),
    224                    StrFixedLenField("phone_number", '', 64),
    225                    StrFixedLenField("subaddress", '', 64)]
    226 
    227 _PPTP_result_code = {1: "Connected",
    228                      2: "General error",
    229                      3: "No Carrier",
    230                      4: "Busy",
    231                      5: "No dial tone",
    232                      6: "Time-out",
    233                      7: "Do not accept"}
    234 
    235 
    236 class PPTPOutgoingCallReply(PPTP):
    237     name = "PPTP Outgoing Call Reply"
    238     fields_desc = [LenField("len", 32),
    239                    ShortEnumField("type", 1, _PPTP_msg_type),
    240                    XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
    241                    ShortEnumField("ctrl_msg_type", 8, _PPTP_ctrl_msg_type),
    242                    XShortField("reserved_0", 0x0000),
    243                    ShortField("call_id", 1),
    244                    ShortField("peer_call_id", 1),
    245                    ByteEnumField("result_code", 1, _PPTP_result_code),
    246                    ByteEnumField("error_code", 0, _PPTP_general_error_code),
    247                    ShortField("cause_code", 0),
    248                    IntField("connect_speed", 100000000),
    249                    ShortField("pkt_window_size", 16),
    250                    ShortField("pkt_proc_delay", 0),
    251                    IntField("channel_id", 0)]
    252 
    253     def answers(self, other):
    254         return isinstance(other, PPTPOutgoingCallRequest) and other.call_id == self.peer_call_id
    255 
    256 
    257 class PPTPIncomingCallRequest(PPTP):
    258     name = "PPTP Incoming Call Request"
    259     fields_desc = [LenField("len", 220),
    260                    ShortEnumField("type", 1, _PPTP_msg_type),
    261                    XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
    262                    ShortEnumField("ctrl_msg_type", 9, _PPTP_ctrl_msg_type),
    263                    XShortField("reserved_0", 0x0000),
    264                    ShortField("call_id", 1),
    265                    ShortField("call_serial_number", 1),
    266                    IntEnumField("bearer_type", 3, _PPTP_bearer_type),
    267                    IntField("channel_id", 0),
    268                    ShortField("dialed_number_len", 0),
    269                    ShortField("dialing_number_len", 0),
    270                    StrFixedLenField("dialed_number", "", 64),
    271                    StrFixedLenField("dialing_number", "", 64),
    272                    StrFixedLenField("subaddress", "", 64)]
    273 
    274 
    275 class PPTPIncomingCallReply(PPTP):
    276     name = "PPTP Incoming Call Reply"
    277     fields_desc = [LenField("len", 148),
    278                    ShortEnumField("type", 1, _PPTP_msg_type),
    279                    XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
    280                    ShortEnumField("ctrl_msg_type", 10, _PPTP_ctrl_msg_type),
    281                    XShortField("reserved_0", 0x0000),
    282                    ShortField("call_id", 1),
    283                    ShortField("peer_call_id", 1),
    284                    ByteEnumField("result_code", 1, _PPTP_result_code),
    285                    ByteEnumField("error_code", 0, _PPTP_general_error_code),
    286                    ShortField("pkt_window_size", 64),
    287                    ShortField("pkt_transmit_delay", 0),
    288                    XShortField("reserved_1", 0x0000)]
    289 
    290     def answers(self, other):
    291         return isinstance(other, PPTPIncomingCallRequest) and other.call_id == self.peer_call_id
    292 
    293 
    294 class PPTPIncomingCallConnected(PPTP):
    295     name = "PPTP Incoming Call Connected"
    296     fields_desc = [LenField("len", 28),
    297                    ShortEnumField("type", 1, _PPTP_msg_type),
    298                    XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
    299                    ShortEnumField("ctrl_msg_type", 11, _PPTP_ctrl_msg_type),
    300                    XShortField("reserved_0", 0x0000),
    301                    ShortField("peer_call_id", 1),
    302                    XShortField("reserved_1", 0x0000),
    303                    IntField("connect_speed", 100000000),
    304                    ShortField("pkt_window_size", 64),
    305                    ShortField("pkt_transmit_delay", 0),
    306                    IntEnumField("framing_type", 1, _PPTP_framing_type)]
    307 
    308     def answers(self, other):
    309         return isinstance(other, PPTPIncomingCallReply) and other.call_id == self.peer_call_id
    310 
    311 
    312 class PPTPCallClearRequest(PPTP):
    313     name = "PPTP Call Clear Request"
    314     fields_desc = [LenField("len", 16),
    315                    ShortEnumField("type", 1, _PPTP_msg_type),
    316                    XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
    317                    ShortEnumField("ctrl_msg_type", 12, _PPTP_ctrl_msg_type),
    318                    XShortField("reserved_0", 0x0000),
    319                    ShortField("call_id", 1),
    320                    XShortField("reserved_1", 0x0000)]
    321 
    322 _PPTP_call_disconnect_result = {1: "Lost Carrier",
    323                                 2: "General error",
    324                                 3: "Admin Shutdown",
    325                                 4: "Request"}
    326 
    327 
    328 class PPTPCallDisconnectNotify(PPTP):
    329     name = "PPTP Call Disconnect Notify"
    330     fields_desc = [LenField("len", 148),
    331                    ShortEnumField("type", 1, _PPTP_msg_type),
    332                    XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
    333                    ShortEnumField("ctrl_msg_type", 13, _PPTP_ctrl_msg_type),
    334                    XShortField("reserved_0", 0x0000),
    335                    ShortField("call_id", 1),
    336                    ByteEnumField("result_code", 1,
    337                                  _PPTP_call_disconnect_result),
    338                    ByteEnumField("error_code", 0, _PPTP_general_error_code),
    339                    ShortField("cause_code", 0),
    340                    XShortField("reserved_1", 0x0000),
    341                    StrFixedLenField("call_statistic", "", 128)]
    342 
    343 
    344 class PPTPWANErrorNotify(PPTP):
    345     name = "PPTP WAN Error Notify"
    346     fields_desc = [LenField("len", 40),
    347                    ShortEnumField("type", 1, _PPTP_msg_type),
    348                    XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
    349                    ShortEnumField("ctrl_msg_type", 14, _PPTP_ctrl_msg_type),
    350                    XShortField("reserved_0", 0x0000),
    351                    ShortField("peer_call_id", 1),
    352                    XShortField("reserved_1", 0x0000),
    353                    IntField("crc_errors", 0),
    354                    IntField("framing_errors", 0),
    355                    IntField("hardware_overruns", 0),
    356                    IntField("buffer_overruns", 0),
    357                    IntField("time_out_errors", 0),
    358                    IntField("alignment_errors", 0)]
    359 
    360 
    361 class PPTPSetLinkInfo(PPTP):
    362     name = "PPTP Set Link Info"
    363     fields_desc = [LenField("len", 24),
    364                    ShortEnumField("type", 1, _PPTP_msg_type),
    365                    XIntField("magic_cookie", _PPTP_MAGIC_COOKIE),
    366                    ShortEnumField("ctrl_msg_type", 15, _PPTP_ctrl_msg_type),
    367                    XShortField("reserved_0", 0x0000),
    368                    ShortField("peer_call_id", 1),
    369                    XShortField("reserved_1", 0x0000),
    370                    XIntField("send_accm", 0x00000000),
    371                    XIntField("receive_accm", 0x00000000)]
    372 
    373 bind_layers(TCP, PPTP, sport=1723)
    374 bind_layers(TCP, PPTP, dport=1723)
    375