Guest User

Untitled

a guest
Oct 21st, 2017
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.95 KB | None | 0 0
  1. """CIDR blocks share the first part of the bit sequence that comprises the
  2. binary representation of the IP address
  3.  
  4. We determine the network portion of the address by applying a bitwise AND
  5. operation to between the address and the netmask. A bitwise AND operation will
  6. basically save the networking portion of the address and discard the host
  7. portion.
  8.  
  9. In the CIDR notation 192.0.1.0/24, the prefix is 192.0.1.0, and the total number
  10. of bits in the address is 24. The least significant 8 bits are the IP addresses
  11. that are part of this CIDR block.
  12.  
  13. 10.10.1.16/32 is an address prefix with 32 bits, which is the highest number of
  14. bits allowed in IPv4.
  15.  
  16. For example, we could express the idea that the IP address 192.168.0.15 is
  17. associated with the netmask 255.255.255.0 by using the CIDR notation of
  18. 92.168.0.15/24. This means that the first 24 bits of the IP address given are
  19. considered significant for the network routing.
  20. """
  21. import re
  22.  
  23. class InvalidIPError(Exception):
  24. pass
  25.  
  26. class Ip(object):
  27. def __init__(self, decimal=None, binary=None):
  28. """Initialize an IP address given either its decimal (192.168.0.0) or
  29. binary (32 characters, each of which is 0 or 1) form"""
  30. if decimal is not None:
  31. self.raw = decimal
  32. self.decimal = self.raw
  33. self.binary = self._binary_from_decimal()
  34. elif binary is not None:
  35. self.raw = binary
  36. self.binary = binary
  37. self.decimal = self._decimal_from_binary()
  38.  
  39. self._verify()
  40.  
  41. def _verify(self):
  42. """Perform a quick validation that the decimal representation of the
  43. IP address is valid
  44. """
  45. octets = [int(x) for x in self.decimal.split(".")]
  46.  
  47. if len(octets) != 4:
  48. raise InvalidIPError("{} is not a valid IP".format(self.decimal))
  49.  
  50. for octet in octets:
  51. if octet not in range(256):
  52. raise InvalidIPError("{} is not a valid IP".format(
  53. self.decimal))
  54.  
  55. def _decimal_from_binary(self):
  56. """Takes a binary IP address and translates to decimal"""
  57. octets = []
  58. for i in range(0, len(self.binary), 8):
  59. frac = self.binary[i:i + 8]
  60. octets.append(str(int(frac, 2)))
  61. return ".".join(octets)
  62.  
  63. def _binary_from_decimal(self):
  64. """Takes a decimal IP address and translates to binary"""
  65. binrep = ""
  66. for octet in self.raw.split("."):
  67. binrep += "{0:b}".format(int(octet)).zfill(8)
  68. return binrep
  69.  
  70.  
  71. class Netmask(object):
  72. """Object represents the part after the / in a CIDR block"""
  73. def __init__(self, input_string):
  74. self.raw = input_string
  75. self.decimal = int(input_string)
  76. self.binary = self._binary()
  77.  
  78. def _binary(self):
  79. """Return a string with `netmask` 1's padded up to 32 characters with
  80. zeroes
  81. """
  82. return "1"*self.decimal + "0"*(32-self.decimal)
  83.  
  84.  
  85. class Cidr(object):
  86. """Class representing a CIDR block"""
  87.  
  88. def __init__(self, input_string):
  89. # Match a regex against x.x.x.x/y
  90. result = re.match(
  91. "(?P<ip>^[0-9]+.[0-9]+.[0-9]+.[0-9]+)/(?P<netmask>[0-9]{1,2})",
  92. input_string)
  93.  
  94. self.ip = Ip(decimal=result.group("ip"))
  95. self.netmask = Netmask(result.group("netmask"))
  96. self.network_prefix = self._get_network_prefix()
  97.  
  98. def _get_network_prefix(self):
  99. """Make a binary representation of the network prefix. This will match
  100. the IP address of the CIDR block up to the first netmask bytes.
  101.  
  102. Returns a string, 32 characters in length
  103. """
  104. np = ""
  105. for letter in zip(self.ip.binary, self.netmask.binary):
  106. # bitwise AND the binary IP with the binary netmask
  107. np += "1" if letter[0] == "1" and letter[1] == "1" else "0"
  108. return np
  109.  
  110. def enumerate_ips(self):
  111. """Yield an Ip for each IP address inside of this CIDR block"""
  112.  
  113. if self.netmask.decimal == 32:
  114. yield Ip(binary=self.network_prefix)
  115. raise StopIteration
  116.  
  117. max_val = 2 ** (32-self.netmask.decimal)
  118.  
  119. for i in range(max_val):
  120. binary_rep = (self.network_prefix[:self.netmask.decimal] +
  121. "{0:b}".format(i).zfill(32-self.netmask.decimal))
  122. yield Ip(binary=binary_rep)
  123.  
  124.  
  125. def test_enumeration():
  126.  
  127. # Test a single IP
  128. single_ip = list(Cidr("128.128.128.128/32").enumerate_ips())
  129. assert len(single_ip) == 1
  130. assert single_ip[0].decimal == "128.128.128.128"
  131.  
  132. # Do a non-power of two netmask
  133. cidr = Cidr("192.168.50.48/30")
  134. expected = ["192.168.50.48", "192.168.50.49", "192.168.50.50",
  135. "192.168.50.51"]
  136. for res in zip(expected, list(cidr.enumerate_ips())):
  137. assert res[1].decimal == res[0]
  138.  
  139. # Check the length of a larger list
  140. assert len(list(Cidr("127.0.0.0/16").enumerate_ips())) == 65536
  141.  
  142.  
  143. if __name__ == "__main__":
  144. print "Testing IP enumerator..."
  145. test_enumeration()
  146. print "Tests passed"
Add Comment
Please, Sign In to add comment