Skip to content

Instantly share code, notes, and snippets.

@vxst
Last active May 13, 2024 10:16
Show Gist options
  • Save vxst/2a25864725fad34ac677ed2342e02655 to your computer and use it in GitHub Desktop.
Save vxst/2a25864725fad34ac677ed2342e02655 to your computer and use it in GitHub Desktop.
#!/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