import random import socket import struct from abc import ABCMeta, abstractmethod import ipaddress from six import text_type __author__ = 'itamar' class NetworkRange(object): __metaclass__ = ABCMeta def __init__(self, shuffle=True): self._shuffle = shuffle def get_range(self): """ :return: Returns a sequence of IPs in an internal format (might be numbers) """ return self._get_range() def __iter__(self): """ Iterator of ip addresses (strings) from the current range. Use get_range if you want it in one go. :return: """ base_range = self.get_range() if self._shuffle: random.shuffle(base_range) for x in base_range: yield self._number_to_ip(x) @abstractmethod def is_in_range(self, ip_address): raise NotImplementedError() @abstractmethod def _get_range(self): raise NotImplementedError() @staticmethod def get_range_obj(address_str): address_str = address_str.strip() if not address_str: # Empty string return None if -1 != address_str.find('-'): return IpRange(ip_range=address_str) if -1 != address_str.find('/'): return CidrRange(cidr_range=address_str) return SingleIpRange(ip_address=address_str) @staticmethod def _ip_to_number(address): return struct.unpack(">L", socket.inet_aton(address))[0] @staticmethod def _number_to_ip(num): return socket.inet_ntoa(struct.pack(">L", num)) class CidrRange(NetworkRange): def __init__(self, cidr_range, shuffle=True): super(CidrRange, self).__init__(shuffle=shuffle) self._cidr_range = cidr_range.strip() self._ip_network = ipaddress.ip_network(text_type(self._cidr_range), strict=False) def __repr__(self): return "" % (self._cidr_range,) def is_in_range(self, ip_address): return ipaddress.ip_address(ip_address) in self._ip_network def _get_range(self): return [CidrRange._ip_to_number(str(x)) for x in self._ip_network if x != self._ip_network.broadcast_address] class IpRange(NetworkRange): def __init__(self, ip_range=None, lower_end_ip=None, higher_end_ip=None, shuffle=True): super(IpRange, self).__init__(shuffle=shuffle) if ip_range is not None: addresses = ip_range.split('-') if len(addresses) != 2: raise ValueError('Illegal IP range format: %s. Format is 192.168.0.5-192.168.0.20' % ip_range) self._lower_end_ip, self._higher_end_ip = [x.strip() for x in addresses] elif (lower_end_ip is not None) and (higher_end_ip is not None): self._lower_end_ip = lower_end_ip.strip() self._higher_end_ip = higher_end_ip.strip() else: raise ValueError('Illegal IP range: %s' % ip_range) self._lower_end_ip_num = self._ip_to_number(self._lower_end_ip) self._higher_end_ip_num = self._ip_to_number(self._higher_end_ip) if self._higher_end_ip_num < self._lower_end_ip_num: raise ValueError( 'Higher end IP %s is smaller than lower end IP %s' % (self._lower_end_ip, self._higher_end_ip)) def __repr__(self): return "" % (self._lower_end_ip, self._higher_end_ip) def is_in_range(self, ip_address): return self._lower_end_ip_num <= self._ip_to_number(ip_address) <= self._higher_end_ip_num def _get_range(self): return range(self._lower_end_ip_num, self._higher_end_ip_num + 1) class SingleIpRange(NetworkRange): def __init__(self, ip_address, shuffle=True): super(SingleIpRange, self).__init__(shuffle=shuffle) self._ip_address = ip_address def __repr__(self): return "" % (self._ip_address,) def is_in_range(self, ip_address): return self._ip_address == ip_address def _get_range(self): return [SingleIpRange._ip_to_number(self._ip_address)]