aboutsummaryrefslogtreecommitdiff
path: root/scripts/rpki/resource_set.py
blob: a0e71566575b13afc19de1402fb824fc0d74251f (plain) (blame)
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
# $Id$

import re, ipaddrs

class resource_range(object):
  """
  Generic resource range type.  Assumes underlying type is some kind of integer.
  You probably don't want to use this type directly.
  """

  def __init__(self, min, max):
    assert min <= max, "Mis-ordered range: %s before %s" % (str(min), str(max))
    self.min = min
    self.max = max

  def __cmp__(self, other):
    c = self.min - other.min
    if c == 0:
      c = self.max - other.max
    return c

class resource_range_as(resource_range):
  """
  Range of Autonomous System Numbers.
  Denote a single ASN by a range whose min and max values are identical.
  """

  def __str__(self):
    if self.min == self.max:
      return str(self.min)
    else:
      return str(self.min) + "-" + str(self.max)

class resource_range_ip(resource_range):
  """
  Range of (generic) IP addresses.  Prefixes are converted to ranges
  on input, and ranges that can be represented as prefixes are written
  as prefixes on output.
  """

  def __str__(self):
    mask = self.min ^ self.max
    prefixlen = self.min.bits
    while mask & 1:
      prefixlen -= 1
      mask >>= 1
    if mask:
      return str(self.min) + "-" + str(self.max)
    else:
      return str(self.min) + "/" + str(prefixlen)

class resource_range_ipv4(resource_range_ip):
  """
  Range of IPv4 addresses.
  """
  pass

class resource_range_ipv6(resource_range_ip):
  """
  Range of IPv6 addresses.
  """
  pass

class resource_set(list):
  """
  Generic resource set.  List type containing resource ranges.
  You probably don't want to use this type directly.
  """

  def __init__(self, s):
    if s:
      self.extend(map(self.parse, s.split(",")))
      self.sort()
      if __debug__:
        for i in range(0, len(self) - 1):
          assert self[i].max < self[i + 1].min, 'Resource overlap "%s"' % (s)

  def __str__(self):
    return ",".join(map(str, self))

class resource_set_as(resource_set):
  """
  ASN resource set.
  """

  def parse(self, x):
    r = re.match("^([0-9]+)-([0-9]+)$", x)
    if r:
      return resource_range_as(long(r.group(1)), long(r.group(2)))
    else:
      return resource_range_as(long(x), long(x))

class resource_set_ip(resource_set):
  """
  (Generic) IP address resource set.
  You probably don't want to use this type directly.
  """

  def parse(self, x):
    r = re.match("^([0-9:.a-fA-F]+)-([0-9:.a-fA-F]+)$", x)
    if r:
      return self.range_type(self.addr_type(r.group(1)), self.addr_type(r.group(2)))
    r = re.match("^([0-9:.a-fA-F]+)/([0-9]+)$", x)
    if r:
      min = self.addr_type(r.group(1))
      prefixlen = int(r.group(2))
      mask = (1 << (self.addr_type.bits - prefixlen)) - 1
      assert (min & mask) == 0, "Resource not in canonical form: %s" % (x)
      max = min | mask
      return self.range_type(min, max)
    raise RuntimeError, 'Bad IP resource "%s"' % (x)

class resource_set_ipv4(resource_set_ip):
  """
  IPv4 address resource set.
  """

  addr_type = ipaddrs.v4addr
  range_type = resource_range_ipv4

class resource_set_ipv6(resource_set_ip):
  """
  IPv6 address resource set.
  """

  addr_type = ipaddrs.v6addr
  range_type = resource_range_ipv6