Last active
May 13, 2024 10:16
-
-
Save vxst/2a25864725fad34ac677ed2342e02655 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" Create a random IPv6 address securely | |
This script creates a random IPv6 address within a given CIDR range. | |
It utilizes the Python secrets module to generate a securely random | |
address for various uses (e.g., allocating DHCP addresses). | |
Use of this source code is governed by an MIT-style license | |
that can be found at https://opensource.org/licenses/MIT. | |
Author: Chunqing Shan <shantingst@gmail.com> | |
""" | |
import ipaddress | |
import argparse | |
import secrets | |
from typing import Union | |
def secrets_randint(a: int, b: int) -> int: | |
""" | |
Generate a random integer between a and b (inclusive) using the secrets module. | |
:param a: The lower bound of the range. | |
:param b: The upper bound of the range. | |
:return: A random integer between a and b (inclusive). | |
""" | |
# Ensure valid input | |
if a > b: | |
raise ValueError("Lower bound must not be greater than upper bound") | |
# Calculate the range and determine the necessary bits | |
num_range = b - a + 1 | |
bits_needed = num_range.bit_length() | |
# Generate a random number with 10 additional bits to ensure a more uniform distribution | |
bits_needed += 10 | |
# Generate a random number that could potentially cover the range from a to b | |
number = secrets.randbits(bits_needed) | |
number = number % num_range | |
# Adjust the number to fall within the specified range and return | |
return number + a | |
def generate_random_ipv6_address(ipv6_prefix: str) -> str: | |
""" | |
Generate a random IPv6 address within the specified prefix range. | |
:param ipv6_prefix: The IPv6 prefix in CIDR notation. | |
:return: A randomly generated IPv6 address within the prefix range. | |
""" | |
# Convert the input IPv6 prefix into an IPv6 network object | |
network = ipaddress.IPv6Network(ipv6_prefix) | |
# Calculate the number of addresses within the network | |
num_addresses = network.num_addresses | |
# Generate a random offset from 1 to the number of addresses in the network, exclusive | |
random_offset = secrets_randint(1, num_addresses - 1) | |
# Add the random offset to the network's base address to generate a random address within the network | |
random_address = network.network_address + random_offset | |
return str(random_address) | |
def main() -> None: | |
""" | |
The CLI. | |
""" | |
# Set up command-line argument parsing | |
parser = argparse.ArgumentParser(description="Generate a random IPv6 address within a specified prefix range") | |
parser.add_argument('ipv6_prefix', type=str, help="IPv6 prefix in CIDR notation") | |
parser.add_argument('-s', '--silent', action='store_true', help="Only output the generated IPv6 address") | |
args = parser.parse_args() | |
# Generate a random IPv6 address within the provided prefix | |
random_ipv6_address = generate_random_ipv6_address(args.ipv6_prefix) | |
# Print the generated IPv6 address based on the silent flag, useful for integrate with other tools | |
if args.silent: | |
print(random_ipv6_address) | |
else: | |
print(f"Randomly generated IPv6 address: {random_ipv6_address}") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment