summaryrefslogtreecommitdiff
path: root/tests/examplefiles/inet_pton6.dg
blob: 3813d5b879d93cce1036d71bc9aa0dfa4e0d2eb3 (plain)
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
import '/re'
import '/sys'


# IPv6address    =  hexpart [ ":" IPv4address ]
# IPv4address    =  1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
# hexpart        =  [ hexseq ] [ "::" [ hexseq ] ]
# hexseq         =  hex4 *( ":" hex4)
# hex4           =  1*4HEXDIG
hexpart = r'({0}|)(?:::({0}|)|)'.format r'(?:[\da-f]{1,4})(?::[\da-f]{1,4})*'
addrv4  = r'(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})'
addrv6  = re.compile $ r'(?i)(?:{})(?::{})?$'.format hexpart addrv4


# Parse a base-N number given a list of its digits.
#
# :param q: the number of digits in that numeral system
#
# :param digits: an iterable of integers in range [0..q]
#
# :return: a decimal integer
#
base_n = q digits -> foldl (x y -> x * q + y) 0 digits


# Parse a sequence of hexadecimal numbers
#
# :param q: a string of colon-separated base-16 integers
#
# :return: an iterable of Python ints
#
unhex = q -> q and map (p -> int p 16) (q.split ':')


# Parse an IPv6 address as specified in RFC 4291.
#
# :param address: a string, obviously.
#
# :return: an integer which, written in binary form, points to the same node.
#
inet_pton6 = address ->
  not (match = addrv6.match address) => raise $ ValueError 'not a valid IPv6 address'
  start, end, *ipv4 = match.groups!

  is_ipv4 = not $ None in ipv4
  shift   = (7 - start.count ':' - 2 * is_ipv4) * 16

  (end is None and shift) or shift < 0 => raise $ ValueError 'not a valid IPv6 address'
  hexaddr = (base_n 0x10000 (unhex start) << shift) + base_n 0x10000 (unhex $ end or '')
  if (is_ipv4 => (hexaddr << 32) + base_n 0x100 (map int ipv4)) (otherwise => hexaddr)


inet6_type = q -> if
  q == 0 => 'unspecified'
  q == 1 => 'loopback'
  (q >>  32)              == 0x000000000000ffff => 'IPv4-mapped'
  (q >>  64)              == 0xfe80000000000000 => 'link-local'
  (q >> 120)              != 0x00000000000000ff => 'general unicast'
  (q >> 112) % (1 << 4)   == 0x0000000000000000 => 'multicast w/ reserved scope value'
  (q >> 112) % (1 << 4)   == 0x000000000000000f => 'multicast w/ reserved scope value'
  (q >> 112) % (1 << 4)   == 0x0000000000000001 => 'interface-local multicast'
  (q >> 112) % (1 << 4)   == 0x0000000000000004 => 'admin-local multicast'
  (q >> 112) % (1 << 4)   == 0x0000000000000005 => 'site-local multicast'
  (q >> 112) % (1 << 4)   == 0x0000000000000008 => 'organization-local multicast'
  (q >> 112) % (1 << 4)   == 0x000000000000000e => 'global multicast'
  (q >> 112) % (1 << 4)   != 0x0000000000000002 => 'multicast w/ unknown scope value'
  (q >>  24) % (1 << 112) == 0x00000000000001ff => 'solicited-node multicast'
  otherwise => 'link-local multicast'


print $ (x -> inet6_type x, hex x) $ inet_pton6 $ sys.stdin.read!.strip!