More or less like what SLAAC is doing, but without relying on the router advertisment.
pip install netifaces
python ./generate-ipv6.py "eth0" "2001:db8:abcd"
import netifaces as ni | |
import re | |
import argparse | |
import ipaddress | |
def get_mac_address(interface): | |
try: | |
interface_details = ni.ifaddresses(interface) | |
mac_address = interface_details[ni.AF_LINK][0]['addr'] | |
return mac_address | |
except (ValueError, KeyError): | |
raise ValueError(f"No MAC address found for interface {interface}") | |
def mac_to_eui64(mac, ipv6_network): | |
# Remove any non-hexadecimal characters from MAC | |
mac = re.sub(r'[^0-9a-fA-F]', '', mac) | |
mac_bytes = bytes.fromhex(mac) | |
# Flip the universal/local bit of the MAC address | |
mac_bytes = bytearray(mac_bytes) | |
mac_bytes[0] ^= 0b00000010 | |
# Insert ff:fe in the middle of the MAC to form EUI-64 | |
eui64 = mac_bytes[:3] + b'\xff\xfe' + mac_bytes[3:] | |
eui64 = int.from_bytes(eui64, byteorder='big') | |
# Calculate full IPv6 address within the network | |
full_ipv6_address = ipaddress.IPv6Address(ipv6_network.network_address + eui64) | |
return full_ipv6_address | |
def main(): | |
parser = argparse.ArgumentParser(description="Generate an IPv6 address from a network device MAC address and an IPv6 prefix with a network mask.") | |
parser.add_argument("interface_name", type=str, help="Network interface name") | |
parser.add_argument("ipv6_network", type=str, help="IPv6 network with prefix, e.g., xxxx:xxxx:xxxx::/xx") | |
args = parser.parse_args() | |
try: | |
ipv6_network = ipaddress.IPv6Network(args.ipv6_network, strict=False) | |
mac_address = get_mac_address(args.interface_name) | |
ipv6_address = mac_to_eui64(mac_address, ipv6_network) | |
print(f"Generated IPv6 Address: {ipv6_address} from MAC Address: {mac_address}") | |
except ValueError as e: | |
print(e) | |
except ipaddress.AddressValueError as ave: | |
print("Error: Invalid IPv6 network format.") | |
if __name__ == "__main__": | |
main() |