xref: /freebsd/tests/sys/netinet6/ra.py (revision f6bcc0925f0ea838da5183dc503f847e56d15cc8)
1#
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2024 Klara, Inc.
5# Copyright (c) 2026 Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
6#
7
8import argparse
9import scapy.all as sp
10import sys
11
12
13#
14# Emit a router advertisement with the specified prefix.
15#
16def main():
17    parser = argparse.ArgumentParser("ra.py",
18                                     description="Emits Router Advertisement packets")
19    parser.add_argument('--sendif', nargs=1, required=True,
20                        help='The interface through which the packet will be sent')
21    parser.add_argument('--src', nargs=1, required=True,
22                        help='The source IP address')
23    parser.add_argument('--dst', nargs=1, required=True,
24                        help='The destination IP address')
25    parser.add_argument('--hoplimit', nargs=1, required=False,
26                        type=int, default=255,
27                        help='The hop limit of IPv6 packet')
28    parser.add_argument('--rtrpref', nargs=1, required=False,
29                        type=int, default=1,
30                        help='The router preference advertised')
31    parser.add_argument('--rtrltime', nargs=1, required=False,
32                        type=int, default=1800,
33                        help='The router preference advertised')
34    parser.add_argument('--prefix', nargs=1, required=False,
35                        help='The prefix to be advertised')
36    parser.add_argument('--prefixlen', nargs=1, required=False,
37                        type=int, default=64,
38                        help='The prefix length to be advertised')
39    parser.add_argument('--validlifetime', nargs=1, required=False,
40                        type=int, default=4294967295,
41                        help='The valid lifetime of the prefix')
42    parser.add_argument('--preferredlifetime', nargs=1, required=False,
43                        type=int, default=4294967295,
44                        help='The preferred lifetime of the prefix')
45    parser.add_argument('--route', nargs='*', required=False,
46                        action='extend', type=str, default=[],
47                        help='The route to be advertised')
48    parser.add_argument('--routelen', nargs='*', required=False,
49                        action='extend', type=int, default=[],
50                        help='The route length to be advertised')
51    parser.add_argument('--rtipref', nargs='*', required=False,
52                        action='extend', type=int, default=[],
53                        help='The route info preference advertised')
54    parser.add_argument('--rtiltime', nargs='*', required=False,
55                        action='extend', type=int, default=[],
56                        help='The route info preference advertised')
57
58    args = parser.parse_args()
59    pkt = sp.Ether() / \
60        sp.IPv6(src=args.src, dst=args.dst, hlim=args.hoplimit) / \
61        sp.ICMPv6ND_RA(chlim=64,
62                       prf=args.rtrpref,
63                       routerlifetime=args.rtrltime)
64
65    if (args.prefix):
66        pkt = pkt / \
67            sp.ICMPv6NDOptPrefixInfo(prefix=args.prefix,
68                                     prefixlen=args.prefixlen,
69                                     validlifetime=args.validlifetime,
70                                     preferredlifetime=args.preferredlifetime)
71
72    for i in range(0, len(args.route)):
73        pkt = pkt / \
74            sp.ICMPv6NDOptRouteInfo(prefix=args.route[i],
75                                    plen=args.routelen[i],
76                                    prf=args.rtipref[i],
77                                    rtlifetime=args.rtiltime[i])
78
79    sp.sendp(pkt, iface=args.sendif[0], verbose=False)
80    sys.exit(0)
81
82
83if __name__ == '__main__':
84    main()
85