anonymize_ip.py (3901B) - Raw
1 # https://raw.githubusercontent.com/samuelmeuli/anonymize-ip/7f4faedf64643bd3de3607ab8905c1b1a3f8841a/anonymizeip/anonymize_ip.py 2 3 from ipaddress import ip_address 4 5 6 def anonymize_ip( 7 address, 8 ipv4_mask="255.255.255.0", 9 ipv6_mask="ffff:ffff:ffff:ffff:0000:0000:0000:0000" 10 ): 11 """ 12 Anonymize the provided IPv4 or IPv6 address by setting parts of the 13 address to 0 14 15 :param str|int address: IP address to be anonymized 16 :param str ipv4_mask: Mask that defines which parts of an IPv4 address are 17 set to 0 (default: "255.255.255.0") 18 :param str ipv6_mask: Mask that defines which parts of an IPv6 address are 19 set to 0 (default: "ffff:ffff:ffff:ffff:0000:0000:0000:0000") 20 :return: Anonymized IP address 21 :rtype: str 22 """ 23 24 # IP address to be anonymized 25 address_packed = ip_address(address).packed 26 address_len = len(address_packed) 27 28 if address_len == 4: 29 # IPv4 30 ipv4_mask_packed = ip_address(ipv4_mask).packed 31 __validate_ipv4_mask(ipv4_mask_packed) 32 return __apply_mask(address_packed, ipv4_mask_packed, 4) 33 elif address_len == 16: 34 # IPv6 35 ipv6_mask_packed = ip_address(ipv6_mask).packed 36 __validate_ipv6_mask(ipv6_mask_packed) 37 return __apply_mask(address_packed, ipv6_mask_packed, 16) 38 else: 39 # Invalid address 40 raise ValueError("Address does not consist of 4 (IPv4) or 16 (IPv6) " 41 "octets") 42 43 44 def __apply_mask(address_packed, mask_packed, nr_bytes): 45 """ 46 Perform a bitwise AND operation on all corresponding bytes between the 47 mask and the provided address. Mask parts set to 0 will become 0 in the 48 anonymized IP address as well 49 50 :param bytes address_packed: Binary representation of the IP address to 51 be anonymized 52 :param bytes mask_packed: Binary representation of the corresponding IP 53 address mask 54 :param int nr_bytes: Number of bytes in the address (4 for IPv4, 16 for 55 IPv6) 56 :return: Anonymized IP address 57 :rtype: str 58 """ 59 60 anon_packed = bytearray() 61 for i in range(0, nr_bytes): 62 anon_packed.append(mask_packed[i] & address_packed[i]) 63 return str(ip_address(bytes(anon_packed))) 64 65 66 def __validate_ipv4_mask(mask_packed): 67 # Test that mask only contains valid numbers 68 for byte in mask_packed: 69 if byte != 0 and byte != 255: 70 raise ValueError("ipv4_mask must only contain numbers 0 or 255") 71 72 # Test that IP address does not get anonymized completely 73 if mask_packed == b'\x00\x00\x00\x00': 74 raise ValueError("ipv4_mask cannot be set to \"0.0.0.0\" (all " 75 "anonymized addresses will be 0.0.0.0)") 76 77 # Test that IP address is changed by anonymization 78 if mask_packed == b'\xff\xff\xff\xff': 79 raise ValueError("ipv4_mask cannot be set to \"255.255.255.255\" " 80 "(addresses will not be anonymized)") 81 82 83 def __validate_ipv6_mask(mask_packed): 84 # Test that mask only contains valid numbers 85 for byte in mask_packed: 86 if byte != 0 and byte != 255: 87 raise ValueError("ipv6_mask must only contain numbers 0 or ffff") 88 89 # Test that IP address does not get anonymized completely 90 if ( 91 mask_packed == 92 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' 93 ): 94 raise ValueError("ipv6_mask cannot be set to " 95 "\"0000:0000:0000:0000:0000:0000:0000:0000\" (all " 96 "anonymized addresses will be 0.0.0.0)") 97 98 # Test that IP address is changed by anonymization 99 if ( 100 mask_packed == 101 b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' 102 ): 103 raise ValueError("ipv6_mask cannot be set to " 104 "\"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff\" " 105 "(addresses will not be anonymized)")