1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
| #!/usr/bin/env python3
# scapy 2.6.1 compatible RA forge example
# Save as ipv6_icmpv6_ra_scapy.py and run with sudo/python from your venv
from scapy.all import (
Ether, IPv6,
ICMPv6ND_RA, ICMPv6NDOptSrcLLAddr, ICMPv6NDOptPrefixInfo,
ICMPv6NDOptMTU, ICMPv6NDOptRDNSS,
sendp, conf
)
from scapy.utils import hexdump
# ------------------ USER-CHANGEABLE VARIABLES ------------------
IFACE = "ens160" # interface to send on
SRC_MAC = "00:11:22:33:44:55" # forged source MAC
SRC_IPV6 = "fe80::221:11ff:fe33:4455" # forged IPv6 source (link-local typical)
DST_IPV6 = "ff02::1" # all-nodes multicast
DST_MAC = "33:33:00:00:00:01" # multicast mac for ff02::1
ROUTER_LIFETIME = 1800 # seconds (0 = not a default router)
HOP_LIMIT = 64 # chlim (current hop limit)
REACHABLE_TIME = 0 # milliseconds
RETRANS_TIMER = 3000 # milliseconds (retransmit timer)
# Prefix info (SLAAC)
PREFIX = "2001:db8:dead:beef::"
PREFIX_LEN = 64
VALID_LIFETIME = 3600
PREFERRED_LIFETIME = 1800
ON_LINK_FLAG = 1
AUTONOMOUS_FLAG = 1
# RDNSS (DNS servers) - optional
RDNSS = ["2001:4860:4860::8888", "2001:4860:4860::8844"]
# ------------------ end user vars --------------------------------
conf.iface = IFACE
eth = Ether(src=SRC_MAC, dst=DST_MAC)
ip6 = IPv6(src=SRC_IPV6, dst=DST_IPV6)
# Build a base RA and set common fields.
# Scapy 2.6.1 expects 'retrans_timer' (not 'retransmittimer').
# We set known fields; attempt to set retrans field using a small fallback loop.
ra = ICMPv6ND_RA(
routerlifetime=int(ROUTER_LIFETIME),
chlim=int(HOP_LIMIT),
reachabletime=int(REACHABLE_TIME),
)
# Try to set retransmit timer using common candidate names.
# For scapy 2.6.1 the likely correct name is 'retrans_timer'.
retrans_candidates = ("retrans_timer", "retrans", "retransmit", "retransmittimer")
set_retrans_ok = False
for cand in retrans_candidates:
try:
setattr(ra, cand, int(RETRANS_TIMER))
set_retrans_ok = True
# print which one worked (only if running interactively)
# print("Using retrans field name:", cand)
break
except Exception:
# attribute may not exist — continue trying
pass
if not set_retrans_ok:
# As a last resort, attach raw bytes: build a new RA with correct values by
# setting fields in the _fields_ dict is not recommended here; instead
# inform the user and continue (packet will omit retrans timer).
print("Warning: could not set retransmit timer field on ICMPv6ND_RA; packet will omit it.")
# Attach Source Link-Layer Address option
slla = ICMPv6NDOptSrcLLAddr(lladdr=SRC_MAC)
# Prefix information option (SLAAC)
pinfo = ICMPv6NDOptPrefixInfo(
prefixlen=int(PREFIX_LEN),
L=int(ON_LINK_FLAG),
A=int(AUTONOMOUS_FLAG),
validlifetime=int(VALID_LIFETIME),
preferredlifetime=int(PREFERRED_LIFETIME),
prefix=PREFIX
)
# MTU option
mtu_opt = ICMPv6NDOptMTU(mtu=1500)
# RDNSS (if available in your Scapy)
rdnss_opt = None
if RDNSS:
try:
rdnss_opt = ICMPv6NDOptRDNSS(lifetime=3600, dns=RDNSS)
except Exception:
# Older Scapy builds may not include this option class. Skip if not present.
rdnss_opt = None
# Combine packet
pkt = eth / ip6 / ra / slla / pinfo / mtu_opt
if rdnss_opt:
pkt = pkt / rdnss_opt
# Show packet for confirmation before sending
pkt.show()
print()
hexdump(pkt)
# Send packet once (change count and inter if you want multiple)
sendp(pkt, iface=IFACE, count=1, inter=0.2, verbose=True)
|