1# This file is part of Scapy 2# See http://www.secdev.org/projects/scapy for more information 3# Copyright (C) Philippe Biondi <phil@secdev.org> 4# This program is published under a GPLv2 license 5 6""" 7Classes and functions for layer 2 protocols. 8""" 9 10from __future__ import absolute_import 11from __future__ import print_function 12import os 13import struct 14import time 15import socket 16 17from scapy.ansmachine import AnsweringMachine 18from scapy.arch import get_if_addr, get_if_hwaddr 19from scapy.base_classes import Gen, Net 20from scapy.compat import chb, orb 21from scapy.config import conf 22from scapy import consts 23from scapy.data import ARPHDR_ETHER, ARPHDR_LOOPBACK, ARPHDR_METRICOM, \ 24 DLT_ETHERNET_MPACKET, DLT_LINUX_IRDA, DLT_LINUX_SLL, DLT_LOOP, \ 25 DLT_NULL, ETHER_ANY, ETHER_BROADCAST, ETHER_TYPES, ETH_P_ARP, \ 26 ETH_P_MACSEC 27from scapy.error import warning, ScapyNoDstMacException 28from scapy.fields import ( 29 BCDFloatField, 30 BitField, 31 ByteField, 32 ConditionalField, 33 FCSField, 34 FieldLenField, 35 IP6Field, 36 IPField, 37 IntEnumField, 38 IntField, 39 LenField, 40 MACField, 41 MultipleTypeField, 42 OUIField, 43 ShortEnumField, 44 ShortField, 45 SourceIP6Field, 46 SourceIPField, 47 StrFixedLenField, 48 StrLenField, 49 XByteField, 50 XIntField, 51 XShortEnumField, 52 XShortField, 53) 54from scapy.modules.six import viewitems 55from scapy.packet import bind_layers, Packet 56from scapy.plist import ( 57 PacketList, 58 QueryAnswer, 59 SndRcvList, 60 _PacketList, 61) 62from scapy.sendrecv import sendp, srp, srp1 63from scapy.utils import checksum, hexdump, hexstr, inet_ntoa, inet_aton, \ 64 mac2str, valid_mac, valid_net, valid_net6 65from scapy.compat import ( 66 Any, 67 Callable, 68 Dict, 69 List, 70 Optional, 71 Tuple, 72 Type, 73 Union, 74 cast, 75) 76from scapy.interfaces import NetworkInterface 77if conf.route is None: 78 # unused import, only to initialize conf.route 79 import scapy.route # noqa: F401 80 81 82# type definitions 83_ResolverCallable = Callable[[Packet, Packet], Optional[str]] 84 85################# 86# Tools # 87################# 88 89 90class Neighbor: 91 def __init__(self): 92 # type: () -> None 93 self.resolvers = {} # type: Dict[Tuple[Type[Packet], Type[Packet]], _ResolverCallable] # noqa: E501 94 95 def register_l3(self, l2, l3, resolve_method): 96 # type: (Type[Packet], Type[Packet], _ResolverCallable) -> None 97 self.resolvers[l2, l3] = resolve_method 98 99 def resolve(self, l2inst, l3inst): 100 # type: (Ether, Packet) -> Optional[str] 101 k = l2inst.__class__, l3inst.__class__ 102 if k in self.resolvers: 103 return self.resolvers[k](l2inst, l3inst) 104 return None 105 106 def __repr__(self): 107 # type: () -> str 108 return "\n".join("%-15s -> %-15s" % (l2.__name__, l3.__name__) for l2, l3 in self.resolvers) # noqa: E501 109 110 111conf.neighbor = Neighbor() 112 113# cache entries expire after 120s 114_arp_cache = conf.netcache.new_cache("arp_cache", 120) 115 116 117@conf.commands.register 118def getmacbyip(ip, chainCC=0): 119 # type: (str, int) -> Optional[str] 120 """Return MAC address corresponding to a given IP address""" 121 if isinstance(ip, Net): 122 ip = next(iter(ip)) 123 ip = inet_ntoa(inet_aton(ip or "0.0.0.0")) 124 tmp = [orb(e) for e in inet_aton(ip)] 125 if (tmp[0] & 0xf0) == 0xe0: # mcast @ 126 return "01:00:5e:%.2x:%.2x:%.2x" % (tmp[1] & 0x7f, tmp[2], tmp[3]) 127 iff, _, gw = conf.route.route(ip) 128 if (iff == conf.loopback_name) or (ip in conf.route.get_if_bcast(iff)): 129 return "ff:ff:ff:ff:ff:ff" 130 if gw != "0.0.0.0": 131 ip = gw 132 133 mac = _arp_cache.get(ip) 134 if mac: 135 return mac 136 137 try: 138 res = srp1(Ether(dst=ETHER_BROADCAST) / ARP(op="who-has", pdst=ip), 139 type=ETH_P_ARP, 140 iface=iff, 141 timeout=2, 142 verbose=0, 143 chainCC=chainCC, 144 nofilter=1) 145 except Exception as ex: 146 warning("getmacbyip failed on %s", ex) 147 return None 148 if res is not None: 149 mac = res.payload.hwsrc 150 _arp_cache[ip] = mac 151 return mac 152 return None 153 154 155# Fields 156 157class DestMACField(MACField): 158 def __init__(self, name): 159 # type: (str) -> None 160 MACField.__init__(self, name, None) 161 162 def i2h(self, pkt, x): 163 # type: (Optional[Ether], Optional[str]) -> str 164 if x is None and pkt is not None: 165 try: 166 x = conf.neighbor.resolve(pkt, pkt.payload) 167 except socket.error: 168 pass 169 if x is None: 170 if conf.raise_no_dst_mac: 171 raise ScapyNoDstMacException() 172 else: 173 x = "ff:ff:ff:ff:ff:ff" 174 warning("Mac address to reach destination not found. Using broadcast.") # noqa: E501 175 return super(DestMACField, self).i2h(pkt, x) 176 177 def i2m(self, pkt, x): 178 # type: (Optional[Ether], Optional[str]) -> bytes 179 return MACField.i2m(self, pkt, self.i2h(pkt, x)) 180 181 182class SourceMACField(MACField): 183 __slots__ = ["getif"] 184 185 def __init__(self, name, getif=None): 186 # type: (str, Optional[Any]) -> None 187 MACField.__init__(self, name, None) 188 self.getif = (lambda pkt: pkt.route()[0]) if getif is None else getif 189 190 def i2h(self, pkt, x): 191 # type: (Optional[Packet], Optional[str]) -> str 192 if x is None: 193 iff = self.getif(pkt) 194 if iff is None: 195 iff = conf.iface 196 if iff: 197 try: 198 x = get_if_hwaddr(iff) 199 except Exception as e: 200 warning("Could not get the source MAC: %s" % e) 201 if x is None: 202 x = "00:00:00:00:00:00" 203 return super(SourceMACField, self).i2h(pkt, x) 204 205 def i2m(self, pkt, x): 206 # type: (Optional[Ether], Optional[Any]) -> bytes 207 return MACField.i2m(self, pkt, self.i2h(pkt, x)) 208 209 210# Layers 211 212ETHER_TYPES[0x88a8] = '802_AD' 213ETHER_TYPES[ETH_P_MACSEC] = '802_1AE' 214 215 216class Ether(Packet): 217 name = "Ethernet" 218 fields_desc = [DestMACField("dst"), 219 SourceMACField("src"), 220 XShortEnumField("type", 0x9000, ETHER_TYPES)] 221 __slots__ = ["_defrag_pos"] 222 223 def hashret(self): 224 # type: () -> bytes 225 return struct.pack("H", self.type) + self.payload.hashret() 226 227 def answers(self, other): 228 # type: (Packet) -> int 229 if isinstance(other, Ether): 230 if self.type == other.type: 231 return self.payload.answers(other.payload) 232 return 0 233 234 def mysummary(self): 235 # type: () -> str 236 return self.sprintf("%src% > %dst% (%type%)") 237 238 @classmethod 239 def dispatch_hook(cls, _pkt=None, *args, **kargs): 240 # type: (Optional[bytes], *Any, **Any) -> Type[Packet] 241 if _pkt and len(_pkt) >= 14: 242 if struct.unpack("!H", _pkt[12:14])[0] <= 1500: 243 return Dot3 244 return cls 245 246 247class Dot3(Packet): 248 name = "802.3" 249 fields_desc = [DestMACField("dst"), 250 SourceMACField("src"), 251 LenField("len", None, "H")] 252 253 def extract_padding(self, s): 254 # type: (bytes) -> Tuple[bytes, bytes] 255 tmp_len = self.len 256 return s[:tmp_len], s[tmp_len:] 257 258 def answers(self, other): 259 # type: (Ether) -> int 260 if isinstance(other, Dot3): 261 return self.payload.answers(other.payload) 262 return 0 263 264 def mysummary(self): 265 # type: () -> str 266 return "802.3 %s > %s" % (self.src, self.dst) 267 268 @classmethod 269 def dispatch_hook(cls, _pkt=None, *args, **kargs): 270 # type: (Optional[Any], *Any, **Any) -> Type[Packet] 271 if _pkt and len(_pkt) >= 14: 272 if struct.unpack("!H", _pkt[12:14])[0] > 1500: 273 return Ether 274 return cls 275 276 277class LLC(Packet): 278 name = "LLC" 279 fields_desc = [XByteField("dsap", 0x00), 280 XByteField("ssap", 0x00), 281 ByteField("ctrl", 0)] 282 283 284def l2_register_l3(l2, l3): 285 # type: (Packet, Packet) -> Optional[str] 286 neighbor = conf.neighbor # type: Neighbor 287 return neighbor.resolve(l2, l3.payload) 288 289 290conf.neighbor.register_l3(Ether, LLC, l2_register_l3) 291conf.neighbor.register_l3(Dot3, LLC, l2_register_l3) 292 293 294class CookedLinux(Packet): 295 # Documentation: http://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html 296 name = "cooked linux" 297 # from wireshark's database 298 fields_desc = [ShortEnumField("pkttype", 0, {0: "unicast", 299 1: "broadcast", 300 2: "multicast", 301 3: "unicast-to-another-host", 302 4: "sent-by-us"}), 303 XShortField("lladdrtype", 512), 304 ShortField("lladdrlen", 0), 305 StrFixedLenField("src", b"", 8), 306 XShortEnumField("proto", 0x800, ETHER_TYPES)] 307 308 309class MPacketPreamble(Packet): 310 # IEEE 802.3br Figure 99-3 311 name = "MPacket Preamble" 312 fields_desc = [StrFixedLenField("preamble", b"", length=8), 313 FCSField("fcs", 0, fmt="!I")] 314 315 316class SNAP(Packet): 317 name = "SNAP" 318 fields_desc = [OUIField("OUI", 0x000000), 319 XShortEnumField("code", 0x000, ETHER_TYPES)] 320 321 322conf.neighbor.register_l3(Dot3, SNAP, l2_register_l3) 323 324 325class Dot1Q(Packet): 326 name = "802.1Q" 327 aliastypes = [Ether] 328 fields_desc = [BitField("prio", 0, 3), 329 BitField("id", 0, 1), 330 BitField("vlan", 1, 12), 331 XShortEnumField("type", 0x0000, ETHER_TYPES)] 332 333 def answers(self, other): 334 # type: (Packet) -> int 335 if isinstance(other, Dot1Q): 336 if ((self.type == other.type) and 337 (self.vlan == other.vlan)): 338 return self.payload.answers(other.payload) 339 else: 340 return self.payload.answers(other) 341 return 0 342 343 def default_payload_class(self, pay): 344 # type: (bytes) -> Type[Packet] 345 if self.type <= 1500: 346 return LLC 347 return conf.raw_layer 348 349 def extract_padding(self, s): 350 # type: (bytes) -> Tuple[bytes, Optional[bytes]] 351 if self.type <= 1500: 352 return s[:self.type], s[self.type:] 353 return s, None 354 355 def mysummary(self): 356 # type: () -> str 357 if isinstance(self.underlayer, Ether): 358 return self.underlayer.sprintf("802.1q %Ether.src% > %Ether.dst% (%Dot1Q.type%) vlan %Dot1Q.vlan%") # noqa: E501 359 else: 360 return self.sprintf("802.1q (%Dot1Q.type%) vlan %Dot1Q.vlan%") 361 362 363conf.neighbor.register_l3(Ether, Dot1Q, l2_register_l3) 364 365 366class STP(Packet): 367 name = "Spanning Tree Protocol" 368 fields_desc = [ShortField("proto", 0), 369 ByteField("version", 0), 370 ByteField("bpdutype", 0), 371 ByteField("bpduflags", 0), 372 ShortField("rootid", 0), 373 MACField("rootmac", ETHER_ANY), 374 IntField("pathcost", 0), 375 ShortField("bridgeid", 0), 376 MACField("bridgemac", ETHER_ANY), 377 ShortField("portid", 0), 378 BCDFloatField("age", 1), 379 BCDFloatField("maxage", 20), 380 BCDFloatField("hellotime", 2), 381 BCDFloatField("fwddelay", 15)] 382 383 384class ARP(Packet): 385 name = "ARP" 386 fields_desc = [ 387 XShortField("hwtype", 0x0001), 388 XShortEnumField("ptype", 0x0800, ETHER_TYPES), 389 FieldLenField("hwlen", None, fmt="B", length_of="hwsrc"), 390 FieldLenField("plen", None, fmt="B", length_of="psrc"), 391 ShortEnumField("op", 1, { 392 "who-has": 1, 393 "is-at": 2, 394 "RARP-req": 3, 395 "RARP-rep": 4, 396 "Dyn-RARP-req": 5, 397 "Dyn-RAR-rep": 6, 398 "Dyn-RARP-err": 7, 399 "InARP-req": 8, 400 "InARP-rep": 9 401 }), 402 MultipleTypeField( 403 [ 404 (SourceMACField("hwsrc"), 405 (lambda pkt: pkt.hwtype == 1 and pkt.hwlen == 6, 406 lambda pkt, val: pkt.hwtype == 1 and ( 407 pkt.hwlen == 6 or (pkt.hwlen is None and 408 (val is None or len(val) == 6 or 409 valid_mac(val))) 410 ))), 411 ], 412 StrFixedLenField("hwsrc", None, length_from=lambda pkt: pkt.hwlen), 413 ), 414 MultipleTypeField( 415 [ 416 (SourceIPField("psrc", "pdst"), 417 (lambda pkt: pkt.ptype == 0x0800 and pkt.plen == 4, 418 lambda pkt, val: pkt.ptype == 0x0800 and ( 419 pkt.plen == 4 or (pkt.plen is None and 420 (val is None or valid_net(val))) 421 ))), 422 (SourceIP6Field("psrc", "pdst"), 423 (lambda pkt: pkt.ptype == 0x86dd and pkt.plen == 16, 424 lambda pkt, val: pkt.ptype == 0x86dd and ( 425 pkt.plen == 16 or (pkt.plen is None and 426 (val is None or valid_net6(val))) 427 ))), 428 ], 429 StrFixedLenField("psrc", None, length_from=lambda pkt: pkt.plen), 430 ), 431 MultipleTypeField( 432 [ 433 (MACField("hwdst", ETHER_ANY), 434 (lambda pkt: pkt.hwtype == 1 and pkt.hwlen == 6, 435 lambda pkt, val: pkt.hwtype == 1 and ( 436 pkt.hwlen == 6 or (pkt.hwlen is None and 437 (val is None or len(val) == 6 or 438 valid_mac(val))) 439 ))), 440 ], 441 StrFixedLenField("hwdst", None, length_from=lambda pkt: pkt.hwlen), 442 ), 443 MultipleTypeField( 444 [ 445 (IPField("pdst", "0.0.0.0"), 446 (lambda pkt: pkt.ptype == 0x0800 and pkt.plen == 4, 447 lambda pkt, val: pkt.ptype == 0x0800 and ( 448 pkt.plen == 4 or (pkt.plen is None and 449 (val is None or valid_net(val))) 450 ))), 451 (IP6Field("pdst", "::"), 452 (lambda pkt: pkt.ptype == 0x86dd and pkt.plen == 16, 453 lambda pkt, val: pkt.ptype == 0x86dd and ( 454 pkt.plen == 16 or (pkt.plen is None and 455 (val is None or valid_net6(val))) 456 ))), 457 ], 458 StrFixedLenField("pdst", None, length_from=lambda pkt: pkt.plen), 459 ), 460 ] 461 462 def hashret(self): 463 # type: () -> bytes 464 return struct.pack(">HHH", self.hwtype, self.ptype, 465 ((self.op + 1) // 2)) + self.payload.hashret() 466 467 def answers(self, other): 468 # type: (Packet) -> int 469 if not isinstance(other, ARP): 470 return False 471 if self.op != other.op + 1: 472 return False 473 # We use a loose comparison on psrc vs pdst to catch answers 474 # with ARP leaks 475 self_psrc = self.get_field('psrc').i2m(self, self.psrc) # type: bytes 476 other_pdst = other.get_field('pdst').i2m(other, other.pdst) \ 477 # type: bytes 478 return self_psrc[:len(other_pdst)] == other_pdst[:len(self_psrc)] 479 480 def route(self): 481 # type: () -> Tuple[Union[NetworkInterface, str, None], Optional[str], Optional[str]] # noqa: E501 482 fld, dst = cast(Tuple[MultipleTypeField, str], 483 self.getfield_and_val("pdst")) 484 fld_inner, dst = fld._find_fld_pkt_val(self, dst) 485 if isinstance(dst, Gen): 486 dst = next(iter(dst)) 487 if isinstance(fld_inner, IP6Field): 488 return conf.route6.route(dst) 489 elif isinstance(fld_inner, IPField): 490 return conf.route.route(dst) 491 else: 492 return None, None, None 493 494 def extract_padding(self, s): 495 # type: (bytes) -> Tuple[bytes, bytes] 496 return b"", s 497 498 def mysummary(self): 499 # type: () -> str 500 if self.op == 1: 501 return self.sprintf("ARP who has %pdst% says %psrc%") 502 if self.op == 2: 503 return self.sprintf("ARP is at %hwsrc% says %psrc%") 504 return self.sprintf("ARP %op% %psrc% > %pdst%") 505 506 507def l2_register_l3_arp(l2, l3): 508 # type: (Type[Packet], Type[Packet]) -> Optional[str] 509 return getmacbyip(l3.pdst) 510 511 512conf.neighbor.register_l3(Ether, ARP, l2_register_l3_arp) 513 514 515class GRErouting(Packet): 516 name = "GRE routing information" 517 fields_desc = [ShortField("address_family", 0), 518 ByteField("SRE_offset", 0), 519 FieldLenField("SRE_len", None, "routing_info", "B"), 520 StrLenField("routing_info", b"", 521 length_from=lambda pkt: pkt.SRE_len), 522 ] 523 524 525class GRE(Packet): 526 name = "GRE" 527 deprecated_fields = { 528 "seqence_number": ("sequence_number", "2.4.4"), 529 } 530 fields_desc = [BitField("chksum_present", 0, 1), 531 BitField("routing_present", 0, 1), 532 BitField("key_present", 0, 1), 533 BitField("seqnum_present", 0, 1), 534 BitField("strict_route_source", 0, 1), 535 BitField("recursion_control", 0, 3), 536 BitField("flags", 0, 5), 537 BitField("version", 0, 3), 538 XShortEnumField("proto", 0x0000, ETHER_TYPES), 539 ConditionalField(XShortField("chksum", None), lambda pkt:pkt.chksum_present == 1 or pkt.routing_present == 1), # noqa: E501 540 ConditionalField(XShortField("offset", None), lambda pkt:pkt.chksum_present == 1 or pkt.routing_present == 1), # noqa: E501 541 ConditionalField(XIntField("key", None), lambda pkt:pkt.key_present == 1), # noqa: E501 542 ConditionalField(XIntField("sequence_number", None), lambda pkt:pkt.seqnum_present == 1), # noqa: E501 543 ] 544 545 @classmethod 546 def dispatch_hook(cls, _pkt=None, *args, **kargs): 547 # type: (Optional[Any], *Any, **Any) -> Type[Packet] 548 if _pkt and struct.unpack("!H", _pkt[2:4])[0] == 0x880b: 549 return GRE_PPTP 550 return cls 551 552 def post_build(self, p, pay): 553 # type: (bytes, bytes) -> bytes 554 p += pay 555 if self.chksum_present and self.chksum is None: 556 c = checksum(p) 557 p = p[:4] + chb((c >> 8) & 0xff) + chb(c & 0xff) + p[6:] 558 return p 559 560 561class GRE_PPTP(GRE): 562 563 """ 564 Enhanced GRE header used with PPTP 565 RFC 2637 566 """ 567 568 name = "GRE PPTP" 569 deprecated_fields = { 570 "seqence_number": ("sequence_number", "2.4.4"), 571 } 572 fields_desc = [BitField("chksum_present", 0, 1), 573 BitField("routing_present", 0, 1), 574 BitField("key_present", 1, 1), 575 BitField("seqnum_present", 0, 1), 576 BitField("strict_route_source", 0, 1), 577 BitField("recursion_control", 0, 3), 578 BitField("acknum_present", 0, 1), 579 BitField("flags", 0, 4), 580 BitField("version", 1, 3), 581 XShortEnumField("proto", 0x880b, ETHER_TYPES), 582 ShortField("payload_len", None), 583 ShortField("call_id", None), 584 ConditionalField(XIntField("sequence_number", None), lambda pkt: pkt.seqnum_present == 1), # noqa: E501 585 ConditionalField(XIntField("ack_number", None), lambda pkt: pkt.acknum_present == 1)] # noqa: E501 586 587 def post_build(self, p, pay): 588 # type: (bytes, bytes) -> bytes 589 p += pay 590 if self.payload_len is None: 591 pay_len = len(pay) 592 p = p[:4] + chb((pay_len >> 8) & 0xff) + chb(pay_len & 0xff) + p[6:] # noqa: E501 593 return p 594 595 596# *BSD loopback layer 597 598class LoIntEnumField(IntEnumField): 599 600 def m2i(self, pkt, x): 601 # type: (Optional[Packet], int) -> int 602 return x >> 24 603 604 def i2m(self, pkt, x): 605 # type: (Optional[Packet], Union[List[int], int, None]) -> int 606 return cast(int, x) << 24 607 608 609# https://github.com/wireshark/wireshark/blob/fe219637a6748130266a0b0278166046e60a2d68/epan/dissectors/packet-null.c 610# https://www.wireshark.org/docs/wsar_html/epan/aftypes_8h.html 611LOOPBACK_TYPES = {0x2: "IPv4", 612 0x7: "OSI", 613 0x10: "Appletalk", 614 0x17: "Netware IPX/SPX", 615 0x18: "IPv6", 0x1c: "IPv6", 0x1e: "IPv6"} 616 617 618class Loopback(Packet): 619 r"""\*BSD loopback layer""" 620 621 name = "Loopback" 622 if consts.OPENBSD: 623 fields_desc = [IntEnumField("type", 0x2, LOOPBACK_TYPES)] 624 else: 625 fields_desc = [LoIntEnumField("type", 0x2, LOOPBACK_TYPES)] 626 __slots__ = ["_defrag_pos"] 627 628 629class Dot1AD(Dot1Q): 630 name = '802_1AD' 631 632 633bind_layers(Dot3, LLC) 634bind_layers(Ether, LLC, type=122) 635bind_layers(Ether, LLC, type=34928) 636bind_layers(Ether, Dot1Q, type=33024) 637bind_layers(Ether, Dot1AD, type=0x88a8) 638bind_layers(Dot1AD, Dot1AD, type=0x88a8) 639bind_layers(Dot1AD, Dot1Q, type=0x8100) 640bind_layers(Dot1Q, Dot1AD, type=0x88a8) 641bind_layers(Ether, Ether, type=1) 642bind_layers(Ether, ARP, type=2054) 643bind_layers(CookedLinux, LLC, proto=122) 644bind_layers(CookedLinux, Dot1Q, proto=33024) 645bind_layers(CookedLinux, Dot1AD, type=0x88a8) 646bind_layers(CookedLinux, Ether, proto=1) 647bind_layers(CookedLinux, ARP, proto=2054) 648bind_layers(MPacketPreamble, Ether) 649bind_layers(GRE, LLC, proto=122) 650bind_layers(GRE, Dot1Q, proto=33024) 651bind_layers(GRE, Dot1AD, type=0x88a8) 652bind_layers(GRE, Ether, proto=0x6558) 653bind_layers(GRE, ARP, proto=2054) 654bind_layers(GRE, GRErouting, {"routing_present": 1}) 655bind_layers(GRErouting, conf.raw_layer, {"address_family": 0, "SRE_len": 0}) 656bind_layers(GRErouting, GRErouting) 657bind_layers(LLC, STP, dsap=66, ssap=66, ctrl=3) 658bind_layers(LLC, SNAP, dsap=170, ssap=170, ctrl=3) 659bind_layers(SNAP, Dot1Q, code=33024) 660bind_layers(SNAP, Dot1AD, type=0x88a8) 661bind_layers(SNAP, Ether, code=1) 662bind_layers(SNAP, ARP, code=2054) 663bind_layers(SNAP, STP, code=267) 664 665conf.l2types.register(ARPHDR_ETHER, Ether) 666conf.l2types.register_num2layer(ARPHDR_METRICOM, Ether) 667conf.l2types.register_num2layer(ARPHDR_LOOPBACK, Ether) 668conf.l2types.register_layer2num(ARPHDR_ETHER, Dot3) 669conf.l2types.register(DLT_LINUX_SLL, CookedLinux) 670conf.l2types.register(DLT_ETHERNET_MPACKET, MPacketPreamble) 671conf.l2types.register_num2layer(DLT_LINUX_IRDA, CookedLinux) 672conf.l2types.register(DLT_LOOP, Loopback) 673conf.l2types.register_num2layer(DLT_NULL, Loopback) 674 675conf.l3types.register(ETH_P_ARP, ARP) 676 677 678# Techniques 679 680 681@conf.commands.register 682def arpcachepoison(target, victim, interval=60): 683 # type: (str, str, int) -> None 684 """Poison target's cache with (your MAC,victim's IP) couple 685arpcachepoison(target, victim, [interval=60]) -> None 686""" 687 tmac = getmacbyip(target) 688 p = Ether(dst=tmac) / ARP(op="who-has", psrc=victim, pdst=target) 689 try: 690 while True: 691 sendp(p, iface_hint=target) 692 if conf.verb > 1: 693 os.write(1, b".") 694 time.sleep(interval) 695 except KeyboardInterrupt: 696 pass 697 698 699class ARPingResult(SndRcvList): 700 def __init__(self, 701 res=None, # type: Optional[Union[_PacketList[QueryAnswer], List[QueryAnswer]]] # noqa: E501 702 name="ARPing", # type: str 703 stats=None # type: Optional[List[Type[Packet]]] 704 ): 705 SndRcvList.__init__(self, res, name, stats) 706 707 def show(self, *args, **kwargs): 708 # type: (*Any, **Any) -> None 709 """ 710 Print the list of discovered MAC addresses. 711 """ 712 713 data = list() 714 padding = 0 715 716 for s, r in self.res: 717 manuf = conf.manufdb._get_short_manuf(r.src) 718 manuf = "unknown" if manuf == r.src else manuf 719 padding = max(padding, len(manuf)) 720 data.append((r[Ether].src, manuf, r[ARP].psrc)) 721 722 for src, manuf, psrc in data: 723 print(" %-17s %-*s %s" % (src, padding, manuf, psrc)) 724 725 726@conf.commands.register 727def arping(net, timeout=2, cache=0, verbose=None, **kargs): 728 # type: (str, int, int, Optional[int], **Any) -> Tuple[ARPingResult, PacketList] # noqa: E501 729 """Send ARP who-has requests to determine which hosts are up 730arping(net, [cache=0,] [iface=conf.iface,] [verbose=conf.verb]) -> None 731Set cache=True if you want arping to modify internal ARP-Cache""" 732 if verbose is None: 733 verbose = conf.verb 734 ans, unans = srp( 735 Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst=net), 736 verbose=verbose, 737 filter="arp and arp[7] = 2", 738 timeout=timeout, 739 iface_hint=net, 740 **kargs 741 ) 742 ans = ARPingResult(ans.res) 743 744 if cache and ans is not None: 745 for pair in ans: 746 _arp_cache[pair[1].psrc] = pair[1].hwsrc 747 if ans is not None and verbose: 748 ans.show() 749 return ans, unans 750 751 752@conf.commands.register 753def is_promisc(ip, fake_bcast="ff:ff:00:00:00:00", **kargs): 754 # type: (str, str, **Any) -> bool 755 """Try to guess if target is in Promisc mode. The target is provided by its ip.""" # noqa: E501 756 757 responses = srp1(Ether(dst=fake_bcast) / ARP(op="who-has", pdst=ip), type=ETH_P_ARP, iface_hint=ip, timeout=1, verbose=0, **kargs) # noqa: E501 758 759 return responses is not None 760 761 762@conf.commands.register 763def promiscping(net, timeout=2, fake_bcast="ff:ff:ff:ff:ff:fe", **kargs): 764 # type: (str, int, str, **Any) -> Tuple[ARPingResult, PacketList] 765 """Send ARP who-has requests to determine which hosts are in promiscuous mode 766 promiscping(net, iface=conf.iface)""" 767 ans, unans = srp(Ether(dst=fake_bcast) / ARP(pdst=net), 768 filter="arp and arp[7] = 2", timeout=timeout, iface_hint=net, **kargs) # noqa: E501 769 ans = ARPingResult(ans.res, name="PROMISCPing") 770 771 ans.display() 772 return ans, unans 773 774 775class ARP_am(AnsweringMachine): 776 """Fake ARP Relay Daemon (farpd) 777 778 example: 779 To respond to an ARP request for 192.168.100 replying on the 780 ingress interface:: 781 782 farpd(IP_addr='192.168.1.100',ARP_addr='00:01:02:03:04:05') 783 784 To respond on a different interface add the interface parameter:: 785 786 farpd(IP_addr='192.168.1.100',ARP_addr='00:01:02:03:04:05',iface='eth0') 787 788 To respond on ANY arp request on an interface with mac address ARP_addr:: 789 790 farpd(ARP_addr='00:01:02:03:04:05',iface='eth1') 791 792 To respond on ANY arp request with my mac addr on the given interface:: 793 794 farpd(iface='eth1') 795 796 Optional Args:: 797 798 inter=<n> Interval in seconds between ARP replies being sent 799 800 """ 801 802 function_name = "farpd" 803 filter = "arp" 804 send_function = staticmethod(sendp) 805 806 def parse_options(self, IP_addr=None, ARP_addr=None): 807 # type: (Optional[str], Optional[str]) -> None 808 self.IP_addr = IP_addr 809 self.ARP_addr = ARP_addr 810 811 def is_request(self, req): 812 # type: (Ether) -> bool 813 if not req.haslayer(ARP): 814 return False 815 arp = req[ARP] 816 return arp.op == 1 and \ 817 (self.IP_addr is None or self.IP_addr == arp.pdst) # noqa: E501 818 819 def make_reply(self, req): 820 # type: (Ether) -> Ether 821 ether = req[Ether] 822 arp = req[ARP] 823 824 if 'iface' in self.optsend: 825 iff = self.optsend.get('iface') 826 else: 827 iff, a, gw = conf.route.route(arp.psrc) 828 self.iff = iff 829 if self.ARP_addr is None: 830 try: 831 ARP_addr = get_if_hwaddr(iff) 832 except Exception: 833 ARP_addr = "00:00:00:00:00:00" 834 else: 835 ARP_addr = self.ARP_addr 836 resp = Ether(dst=ether.src, 837 src=ARP_addr) / ARP(op="is-at", 838 hwsrc=ARP_addr, 839 psrc=arp.pdst, 840 hwdst=arp.hwsrc, 841 pdst=arp.psrc) 842 return resp 843 844 def send_reply(self, reply): 845 # type: (ARP) -> None 846 if 'iface' in self.optsend: 847 self.send_function(reply, **self.optsend) 848 else: 849 self.send_function(reply, iface=self.iff, **self.optsend) 850 851 def print_reply(self, req, reply): 852 # type: (Ether, Ether) -> None 853 print("%s ==> %s on %s" % (req.summary(), reply.summary(), self.iff)) 854 855 856@conf.commands.register 857def etherleak(target, **kargs): 858 # type: (str, **Any) -> Tuple[SndRcvList, PacketList] 859 """Exploit Etherleak flaw""" 860 return srp(Ether() / ARP(pdst=target), 861 prn=lambda s_r: conf.padding_layer in s_r[1] and hexstr(s_r[1][conf.padding_layer].load), # noqa: E501 862 filter="arp", **kargs) 863 864 865@conf.commands.register 866def arpleak(target, plen=255, hwlen=255, **kargs): 867 # type: (str, int, int, **Any) -> Tuple[SndRcvList, PacketList] 868 """Exploit ARP leak flaws, like NetBSD-SA2017-002. 869 870https://ftp.netbsd.org/pub/NetBSD/security/advisories/NetBSD-SA2017-002.txt.asc 871 872 """ 873 # We want explicit packets 874 pkts_iface = {} # type: Dict[str, List[Ether]] 875 for pkt in ARP(pdst=target): 876 # We have to do some of Scapy's work since we mess with 877 # important values 878 iface = conf.route.route(pkt.pdst)[0] 879 psrc = get_if_addr(iface) 880 hwsrc = get_if_hwaddr(iface) 881 pkt.plen = plen 882 pkt.hwlen = hwlen 883 if plen == 4: 884 pkt.psrc = psrc 885 else: 886 pkt.psrc = inet_aton(psrc)[:plen] 887 pkt.pdst = inet_aton(pkt.pdst)[:plen] 888 if hwlen == 6: 889 pkt.hwsrc = hwsrc 890 else: 891 pkt.hwsrc = mac2str(hwsrc)[:hwlen] 892 pkts_iface.setdefault(iface, []).append( 893 Ether(src=hwsrc, dst=ETHER_BROADCAST) / pkt 894 ) 895 ans, unans = SndRcvList(), PacketList(name="Unanswered") 896 for iface, pkts in viewitems(pkts_iface): 897 ans_new, unans_new = srp(pkts, iface=iface, filter="arp", **kargs) 898 ans += ans_new 899 unans += unans_new 900 ans.listname = "Results" 901 unans.listname = "Unanswered" 902 for _, rcv in ans: 903 if ARP not in rcv: 904 continue 905 rcv = rcv[ARP] 906 psrc = rcv.get_field('psrc').i2m(rcv, rcv.psrc) 907 if plen > 4 and len(psrc) > 4: 908 print("psrc") 909 hexdump(psrc[4:]) 910 print() 911 hwsrc = rcv.get_field('hwsrc').i2m(rcv, rcv.hwsrc) 912 if hwlen > 6 and len(hwsrc) > 6: 913 print("hwsrc") 914 hexdump(hwsrc[6:]) 915 print() 916 return ans, unans 917