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