1import '/re' 2import '/sys' 3 4 5# IPv6address = hexpart [ ":" IPv4address ] 6# IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT 7# hexpart = [ hexseq ] [ "::" [ hexseq ] ] 8# hexseq = hex4 *( ":" hex4) 9# hex4 = 1*4HEXDIG 10hexpart = r'({0}|)(?:::({0}|)|)'.format r'(?:[\da-f]{1,4})(?::[\da-f]{1,4})*' 11addrv4 = r'(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})' 12addrv6 = re.compile $ r'(?i)(?:{})(?::{})?$'.format hexpart addrv4 13 14 15# Parse a base-N number given a list of its digits. 16# 17# :param q: the number of digits in that numeral system 18# 19# :param digits: an iterable of integers in range [0..q] 20# 21# :return: a decimal integer 22# 23base_n = q digits -> foldl (x y -> x * q + y) 0 digits 24 25 26# Parse a sequence of hexadecimal numbers 27# 28# :param q: a string of colon-separated base-16 integers 29# 30# :return: an iterable of Python ints 31# 32unhex = q -> q and map (p -> int p 16) (q.split ':') 33 34 35# Parse an IPv6 address as specified in RFC 4291. 36# 37# :param address: a string, obviously. 38# 39# :return: an integer which, written in binary form, points to the same node. 40# 41inet_pton6 = address -> 42 not (match = addrv6.match address) => raise $ ValueError 'not a valid IPv6 address' 43 start, end, *ipv4 = match.groups! 44 45 is_ipv4 = not $ None in ipv4 46 shift = (7 - start.count ':' - 2 * is_ipv4) * 16 47 48 (end is None and shift) or shift < 0 => raise $ ValueError 'not a valid IPv6 address' 49 hexaddr = (base_n 0x10000 (unhex start) << shift) + base_n 0x10000 (unhex $ end or '') 50 if (is_ipv4 => (hexaddr << 32) + base_n 0x100 (map int ipv4)) (otherwise => hexaddr) 51 52 53inet6_type = q -> if 54 q == 0 => 'unspecified' 55 q == 1 => 'loopback' 56 (q >> 32) == 0x000000000000ffff => 'IPv4-mapped' 57 (q >> 64) == 0xfe80000000000000 => 'link-local' 58 (q >> 120) != 0x00000000000000ff => 'general unicast' 59 (q >> 112) % (1 << 4) == 0x0000000000000000 => 'multicast w/ reserved scope value' 60 (q >> 112) % (1 << 4) == 0x000000000000000f => 'multicast w/ reserved scope value' 61 (q >> 112) % (1 << 4) == 0x0000000000000001 => 'interface-local multicast' 62 (q >> 112) % (1 << 4) == 0x0000000000000004 => 'admin-local multicast' 63 (q >> 112) % (1 << 4) == 0x0000000000000005 => 'site-local multicast' 64 (q >> 112) % (1 << 4) == 0x0000000000000008 => 'organization-local multicast' 65 (q >> 112) % (1 << 4) == 0x000000000000000e => 'global multicast' 66 (q >> 112) % (1 << 4) != 0x0000000000000002 => 'multicast w/ unknown scope value' 67 (q >> 24) % (1 << 112) == 0x00000000000001ff => 'solicited-node multicast' 68 otherwise => 'link-local multicast' 69 70 71print $ (x -> inet6_type x, hex x) $ inet_pton6 $ sys.stdin.read!.strip! 72