/usr/share/pyshared/impacket/IP6_Address.py is in python-impacket 0.9.10-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | # Copyright (c) 2003-2012 CORE Security Technologies
#
# This software is provided under under a slightly modified version
# of the Apache Software License. See the accompanying LICENSE file
# for more information.
#
# $Id: IP6_Address.py 529 2012-04-29 21:39:46Z bethus@gmail.com $
#
import array
class IP6_Address():
ADDRESS_BYTE_SIZE = 16
#A Hex Group is a 16-bit unit of the address
TOTAL_HEX_GROUPS = 8
HEX_GROUP_SIZE = 4 #Size in characters
TOTAL_SEPARATORS = TOTAL_HEX_GROUPS - 1
ADDRESS_TEXT_SIZE = (TOTAL_HEX_GROUPS * HEX_GROUP_SIZE) + TOTAL_SEPARATORS
SEPARATOR = ":"
SCOPE_SEPARATOR = "%"
#############################################################################################################
# Constructor and construction helpers
def __init__(self, address):
#The internal representation of an IP6 address is a 16-byte array
self.__bytes = array.array('B', '\0' * self.ADDRESS_BYTE_SIZE)
self.__scope_id = ""
#Invoke a constructor based on the type of the argument
if type(address) is str or type(address) is unicode:
self.__from_string(address)
else:
self.__from_bytes(address)
def __from_string(self, address):
#Separate the Scope ID, if present
if self.__is_a_scoped_address(address):
split_parts = address.split(self.SCOPE_SEPARATOR)
address = split_parts[0]
if (split_parts[1] == ""):
raise Exception("Empty scope ID")
self.__scope_id = split_parts[1]
#Expand address if it's in compressed form
if self.__is_address_in_compressed_form(address):
address = self.__expand_compressed_address(address)
#Insert leading zeroes where needed
address = self.__insert_leading_zeroes(address)
#Sanity check
if len(address) != self.ADDRESS_TEXT_SIZE:
raise Exception('IP6_Address - from_string - address size != ' + str(self.ADDRESS_TEXT_SIZE))
#Split address into hex groups
hex_groups = address.split(self.SEPARATOR)
if len(hex_groups) != self.TOTAL_HEX_GROUPS:
raise Exception('IP6_Address - parsed hex groups != ' + str(self.TOTAL_HEX_GROUPS))
#For each hex group, convert it into integer words
offset = 0
for group in hex_groups:
if len(group) != self.HEX_GROUP_SIZE:
raise Exception('IP6_Address - parsed hex group length != ' + str(self.HEX_GROUP_SIZE))
group_as_int = int(group, 16)
self.__bytes[offset] = (group_as_int & 0xFF00) >> 8
self.__bytes[offset + 1] = (group_as_int & 0x00FF)
offset += 2
def __from_bytes(self, bytes):
if len(bytes) != self.ADDRESS_BYTE_SIZE:
raise Exception ("IP6_Address - from_bytes - array size != " + str(self.ADDRESS_BYTE_SIZE))
self.__bytes = bytes
#############################################################################################################
# Projectors
def as_string(self, compress_address = True, scoped_address = True):
s = ""
for i, v in enumerate(self.__bytes):
s += hex(v)[2:].rjust(2, '0')
if (i % 2 == 1):
s += self.SEPARATOR
s = s[:-1].upper()
if (compress_address):
s = self.__trim_leading_zeroes(s)
s = self.__trim_longest_zero_chain(s)
if (scoped_address and self.get_scope_id() != ""):
s += self.SCOPE_SEPARATOR + self.__scope_id
return s
def as_bytes(self):
return self.__bytes
def __str__(self):
return self.as_string()
def get_scope_id(self):
return self.__scope_id
def get_unscoped_address(self):
return self.as_string(True, False) #Compressed address = True, Scoped address = False
#############################################################################################################
# Semantic helpers
def is_multicast(self):
return self.__bytes[0] == 0xFF
def is_unicast(self):
return self.__bytes[0] == 0xFE
def is_link_local_unicast(self):
return self.is_unicast() and (self.__bytes[1] & 0xC0 == 0x80)
def is_site_local_unicast(self):
return self.is_unicast() and (self.__bytes[1] & 0xC0 == 0xC0)
def is_unique_local_unicast(self):
return (self.__bytes[0] == 0xFD)
def get_human_readable_address_type(self):
if (self.is_multicast()):
return "multicast"
elif (self.is_unicast()):
if (self.is_link_local_unicast()):
return "link-local unicast"
elif (self.is_site_local_unicast()):
return "site-local unicast"
else:
return "unicast"
elif (self.is_unique_local_unicast()):
return "unique-local unicast"
else:
return "unknown type"
#############################################################################################################
#Expansion helpers
#Predicate - returns whether an address is in compressed form
def __is_address_in_compressed_form(self, address):
#Sanity check - triple colon detection (not detected by searches of double colon)
if address.count(self.SEPARATOR * 3) > 0:
raise Exception('IP6_Address - found triple colon')
#Count the double colon marker
compression_marker_count = self.__count_compression_marker(address)
if compression_marker_count == 0:
return False
elif compression_marker_count == 1:
return True
else:
raise Exception('IP6_Address - more than one compression marker (\"::\") found')
#Returns how many hex groups are present, in a compressed address
def __count_compressed_groups(self, address):
trimmed_address = address.replace(self.SEPARATOR * 2, self.SEPARATOR) #Replace "::" with ":"
return trimmed_address.count(self.SEPARATOR) + 1
#Counts how many compression markers are present
def __count_compression_marker(self, address):
return address.count(self.SEPARATOR * 2) #Count occurrences of "::"
#Inserts leading zeroes in every hex group
def __insert_leading_zeroes(self, address):
hex_groups = address.split(self.SEPARATOR)
new_address = ""
for hex_group in hex_groups:
if len(hex_group) < 4:
hex_group = hex_group.rjust(4, "0")
new_address += hex_group + self.SEPARATOR
return new_address[:-1] #Trim the last colon
#Expands a compressed address
def __expand_compressed_address(self, address):
group_count = self.__count_compressed_groups(address)
groups_to_insert = self.TOTAL_HEX_GROUPS - group_count
pos = address.find(self.SEPARATOR * 2) + 1
while (groups_to_insert):
address = address[:pos] + "0000" + self.SEPARATOR + address[pos:]
pos += 5
groups_to_insert -= 1
#Replace the compression marker with a single colon
address = address.replace(self.SEPARATOR * 2, self.SEPARATOR)
return address
#############################################################################################################
#Compression helpers
def __trim_longest_zero_chain(self, address):
chain_size = 8
while (chain_size > 0):
groups = address.split(self.SEPARATOR)
start_index = -1
end_index = -1
for index, group in enumerate(groups):
#Find the first zero
if (group == "0"):
start_index = index
end_index = index
#Find the end of this chain of zeroes
while (end_index < 7 and groups[end_index + 1] == "0"):
end_index += 1
#If the zero chain matches the current size, trim it
found_size = end_index - start_index + 1
if (found_size == chain_size):
address = self.SEPARATOR.join(groups[0:start_index]) + self.SEPARATOR * 2 + self.SEPARATOR.join(groups[(end_index+1):])
return address
#No chain of this size found, try with a lower size
chain_size -= 1
return address
#Trims all leading zeroes from every hex group
def __trim_leading_zeroes(self, str):
groups = str.split(self.SEPARATOR)
str = ""
for group in groups:
group = group.lstrip("0") + self.SEPARATOR
if (group == self.SEPARATOR):
group = "0" + self.SEPARATOR
str += group
return str[:-1]
#############################################################################################################
@classmethod
def is_a_valid_text_representation(cls, text_representation):
try:
#Capitalize on the constructor's ability to detect invalid text representations of an IP6 address
ip6_address = IP6_Address(text_representation)
return True
except Exception, e:
return False
def __is_a_scoped_address(self, text_representation):
return text_representation.count(self.SCOPE_SEPARATOR) == 1
#############################################################################################################
# Informal tests
if __name__ == '__main__':
print IP6_Address("A:B:C:D:E:F:1:2").as_string()
# print IP6_Address("A:B:C:D:E:F:0:2").as_bytes()
print IP6_Address("A:B:0:D:E:F:0:2").as_string()
# print IP6_Address("A::BC:E:D").as_string(False)
print IP6_Address("A::BC:E:D").as_string()
print IP6_Address("A::BCD:EFFF:D").as_string()
print IP6_Address("FE80:0000:0000:0000:020C:29FF:FE26:E251").as_string()
# print IP6_Address("A::BCD:EFFF:D").as_bytes()
print IP6_Address("::").as_string()
print IP6_Address("1::").as_string()
print IP6_Address("::2").as_string()
# bin = [
# 0x01, 0x02, 0x03, 0x04,
# 0x01, 0x02, 0x03, 0x04,
# 0x01, 0x02, 0x03, 0x04,
# 0x01, 0x02, 0x03, 0x04]
# a = IP6_Address(bin)
# print a.as_string()
# print a
# Malformed addresses
# print IP6_Address("ABCD:EFAB:1234:1234:1234:1234:1234:12345").as_string()
# print IP6_Address(":::").as_string()
# print IP6_Address("::::").as_string()
|