class NetGroupRegexPermission(models.Model): group = models.CharField(max_length=80) range = CidrAddressField() regex = models.CharField(max_length=250, validators=[validate_regex]) objects = NetManager() class Meta: db_table = 'perm_net_group_regex' unique_together = ( 'group', 'range', 'regex', ) def __str__(self): return f"group {self.group}, range {self.range}, regex {self.regex}" @staticmethod def find_perm(groups, hostname, ips): if not isinstance(hostname, str): raise ValueError(f'hostname is invalid type ({type(hostname)})') if isinstance(groups, str): groups = [groups] if not isinstance(groups, (list, tuple)): raise ValueError(f'groups on invalid type ({type(groups)})') if isinstance(ips, str): ips = [ips] if not isinstance(ips, (list, tuple)): raise ValueError(f'ips on invalid type ({type(ips)})') qs = NetGroupRegexPermission.objects.filter(group__in=groups).extra( where=["%s ~ regex"], params=[str(hostname)]).filter( reduce(lambda x, y: x | y, [Q(range__net_contains=ip) for ip in ips])) return qs
class GulRecentArpBymac(models.Model): host = models.OneToOneField( "Host", on_delete=models.DO_NOTHING, db_column="mac", db_constraint=False, related_name="mac_history", primary_key=True, ) address = models.ForeignKey( "network.Address", on_delete=models.DO_NOTHING, db_column="address", db_constraint=False, related_name="mac_history", ) stopstamp = models.DateTimeField() objects = NetManager() def __str__(self): return "%s - %s" % (self.pk, self.address) class Meta: db_table = "gul_recent_arp_bymac"
class IP4RTestModel(Model): field = CidrAddressField() objects = NetManager() class Meta: # Table name can't be type name? db_table = 'ip4rtest'
class Token(ExportModelOperationsMixin('Token'), rest_framework.authtoken.models.Token): @staticmethod def _allowed_subnets_default(): return [ ipaddress.IPv4Network('0.0.0.0/0'), ipaddress.IPv6Network('::/0') ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) key = models.CharField("Key", max_length=128, db_index=True, unique=True) user = models.ForeignKey(User, related_name='auth_tokens', on_delete=models.CASCADE, verbose_name="User") name = models.CharField('Name', blank=True, max_length=64) last_used = models.DateTimeField(null=True, blank=True) perm_manage_tokens = models.BooleanField(default=False) allowed_subnets = ArrayField(CidrAddressField(), default=_allowed_subnets_default.__func__) max_age = models.DurationField( null=True, default=None, validators=[MinValueValidator(timedelta(0))]) max_unused_period = models.DurationField( null=True, default=None, validators=[MinValueValidator(timedelta(0))]) plain = None objects = NetManager() @property def is_valid(self): now = timezone.now() # Check max age try: if self.created + self.max_age < now: return False except TypeError: pass # Check regular usage requirement try: if (self.last_used or self.created) + self.max_unused_period < now: return False except TypeError: pass return True def generate_key(self): self.plain = secrets.token_urlsafe(21) self.key = Token.make_hash(self.plain) return self.key @staticmethod def make_hash(plain): return make_password(plain, salt='static', hasher='pbkdf2_sha256_iter1')
class IPRule(Contribution): #ip = models.GenericIPAddressField() ip = CidrAddressField() georesult = models.CharField(max_length=256) canonical_georesult = models.CharField(max_length=256, blank=True, null=True) #granularity = models.CharField(max_length=1, choices=GRANULARITIES ) default city for now lat = models.FloatField(blank=True, null=True) lon = models.FloatField(blank=True, null=True) objects = NetManager() #objects = IPRuleManager() def save(self, *args, **kwargs): if self.georesult: loc = openipmap.geoutils.loc_resolve(self.georesult) if loc and loc.raw['lat'] and loc.raw['lng']: self.lat = loc.raw['lat'] self.lon = loc.raw['lng'] cityname = '' try: cityname = loc.raw['name'] except: pass regionname = '' try: regionname = loc.raw['adminName1'] except: pass countrycode = '' try: countrycode = loc.raw['countryCode'] except: pass self.canonical_georesult = "%s,%s,%s" % (cityname, regionname, countrycode) super(IPRule, self).save(*args, **kwargs) @classmethod def get_crowdsourced(cls, ip, max_results=10): ''' returns 'max_results' number of results for this particular IP from the IPRules tables ''' results = [] ipr = IPRule.objects.filter(ip__net_contains_or_equals=ip) for rule in ipr: results.append({ 'kind': 'ip', 'granularity': 'city', 'lat': rule.lat, 'lon': rule.lon, 'georesult': rule.georesult, 'canonical_georesult': rule.canonical_georesult, 'confidence': rule.confidence, }) return results
class Lab(models.Model): name = models.CharField(max_length=30) building = models.ForeignKey(Building, on_delete=models.CASCADE, related_name='labs') comment = models.CharField(max_length=30, null=True, blank=True) network = CidrAddressField(null=True, blank=True) objects = NetManager() def __str__(self): return self.building.code + '/' + self.name
class MacOui(models.Model): oui = MACAddressField(primary_key=True) vendor = models.TextField() objects = NetManager() def __str__(self): return self.oui class Meta: db_table = "mac_oui"
class UserIpAddress(models.Model): ip = CidrAddressField(unique=True, db_index=True) user = models.ForeignKey(User, related_name='user') objects = NetManager() class Meta: app_label = 'api' db_table = "useripaddress" verbose_name = "User IP Address" verbose_name_plural = "User IP Addresses" def __unicode__(self): return "%s - %s" % (self.ip, self.user)
class Prefix(models.Model): protocol = models.CharField(max_length=8) prefix = CidrAddressField() ixlan_id = models.PositiveIntegerField() objects = NetManager() class Meta: ordering = ["prefix"] verbose_name = "IX Prefix" verbose_name_plural = "IX Prefixes" def __str__(self): return "{} - {}".format(self.protocol, self.prefix)
class PrefixInfo(models.Model): objects = NetManager() TYPE_CHOICES = ((1, "RIR"), (2, "PRIVATE")) asn = models.PositiveIntegerField(blank=True, null=True) prefix = CidrAddressField(unique=True) name = models.CharField(max_length=32) description = models.CharField(max_length=64) country_code = models.CharField(max_length=3) rir = models.CharField(max_length=16, blank=True, null=True) type = models.PositiveSmallIntegerField(choices=TYPE_CHOICES) updated_at = models.DateTimeField(auto_now=True) def __str__(self): return str(self.prefix)
class AttributeToHost(models.Model): attribute = models.IntegerField(null=True, blank=True, db_column="aid") name = models.CharField(max_length=255, blank=True, null=True) structured = models.BooleanField(default=None) required = models.BooleanField(default=False) mac = MACAddressField(blank=True, null=True) avid = models.IntegerField(blank=True, null=True) value = models.TextField(blank=True, null=True) objects = NetManager() def __str__(self): return "%s %s" % (self.attribute.name, self.name) class Meta: managed = False db_table = "attributes_to_hosts"
class NetGroupRegexPermission(BaseModel): group = models.CharField(max_length=80) range = CidrAddressField() regex = models.CharField(max_length=250, validators=[validate_regex]) labels = models.ManyToManyField(Label, blank=True, related_name='permissions') objects = NetManager() class Meta: db_table = 'perm_net_group_regex' unique_together = ( 'group', 'range', 'regex', ) def __str__(self): return f"group {self.group}, range {self.range}, regex {self.regex}" @classmethod def find_perm(cls, groups, hostname, ips, require_ip=True): if not isinstance(hostname, str): raise ValueError(f'hostname is invalid type ({type(hostname)})') if isinstance(groups, str): groups = [groups] if not isinstance(groups, (list, tuple)): raise ValueError(f'groups on invalid type ({type(groups)})') if isinstance(ips, str): ips = [ips] if not isinstance(ips, (list, tuple)): raise ValueError(f'ips on invalid type ({type(ips)})') if require_ip and not ips: return cls.objects.none() if not all([groups, hostname]): return cls.objects.none() qs = cls.objects.filter(group__in=groups).extra(where=["%s ~ regex"], params=[str(hostname)]) if require_ip: qs = qs.filter( reduce(lambda x, y: x | y, [Q(range__net_contains=ip) for ip in ips])) return qs
class Nic(models.Model): model = models.CharField(max_length=30, blank=True) mac = MACAddressField(unique=True) integrated = models.BooleanField(default=False) management = models.BooleanField(default=False) host = models.ForeignKey(Host, on_delete=models.CASCADE, related_name='nics', null=True, blank=True) ip = InetAddressField(store_prefix_length=False, blank=True, null=True) primary = models.BooleanField(help_text="Is this the primary NIC in the assigned host?") lastseen = models.DateTimeField(null=True, blank=True, help_text="Updated automatically from primary LabScan") objects = NetManager() def __str__(self): return str(self.mac) + ' / ' + self.model def clean(self): if self.host: primaries = Nic.objects.filter(Q(primary=True) & Q(host=self.host) & ~Q(pk=self.pk)) if primaries.count() > 1: raise ValidationError(f"The assigned host cannot have more than one primary NIC, id(s) {primaries.all()}") def save(self, *args, **kwargs): self.full_clean() # update the IP fields on the card's parent host if it has one. if self.host!=None and self.ip: if self.primary: self.host.ip = self.ip elif self.host.ip == None: primarynic = self.host.nics.filter(primary=True) if primarynic: if primarynic[0].ip is None: self.host.ip = self.ip if self.host.lastseen: if self.lastseen > self.host.lastseen: self.host.lastseen = self.lastseen else: self.host.lastseen = self.lastseen self.host.save() return super().save(*args, **kwargs)
class IP(models.Model): # https://docs.python.org/3/library/ipaddress.html # inet = InetAddressField(primary_key=True) inet = InetAddressField() open_ports = ArrayField(models.IntegerField(), blank=True, null=True) objects = NetManager() class Meta: verbose_name = _('IP') verbose_name_plural = _('IP-addresses') @classmethod def stat(cls): """Return Port and how many IPs have it open""" return cls.objects \ .annotate(port=Unnest('open_ports', distinct=True)) \ .values('port') \ .annotate(count=Count('port')) \ .order_by('-count', '-port') @classmethod def with_open_ports(cls, ports): """Return Port and how many IPs have it open""" return cls.objects.filter(open_ports__contains=ports) def __str__(self): # from django.contrib.postgres.aggregates import ArrayAgg # print(IP.objects.aggregate(arrayagg=ArrayAgg('inet'))) # print(IP.objects.values('open_ports')\ # .annotate(number_of_days=Count('open_ports', distinct=True))) # print(IP.objects.filter()\ # .aggregate(Avg('open_ports'))) # print(IP.objects.aggregate(All('open_ports'))) # print(IP.stat()) # .group_by('inet')) # print(IP.objects.values('inet').annotate(arr_els=Unnest('open_ports'))) # .values_list('arr_els', flat=True).distinct()) return str(self.inet)
class Ip(BaseAccessLevel): """ IP Address Model """ interface = models.ForeignKey('net.Interface', verbose_name=_('interface')) address = InetAddressField(verbose_name=_('ip address'), unique=True, db_index=True) protocol = models.CharField(_('IP Protocol Version'), max_length=4, choices=IP_PROTOCOLS, default=IP_PROTOCOLS[0][0], blank=True) netmask = CidrAddressField(_('netmask (CIDR, eg: 10.40.0.0/24)')) objects = NetManager() class Meta: app_label = 'net' permissions = (('can_view_ip', 'Can view ip'), ) verbose_name = _('ip address') verbose_name_plural = _('ip addresses') def __unicode__(self): return '%s: %s' % (self.protocol, self.address) def full_clean(self, *args, **kwargs): """ TODO """ pass def save(self, *args, **kwargs): """ Determines ip protocol version automatically """ self.protocol = 'ipv%d' % self.address.version # save super(Ip, self).save(*args, **kwargs) if 'grappelli' in settings.INSTALLED_APPS: @staticmethod def autocomplete_search_fields(): return ('address__icontains', )
class LoginAttempt(models.Model): ''' A login attempt record (both successful and not). If user field is set then login was successful. Instead login and password fields are set. ''' # https://docs.python.org/3/library/ipaddress.html # inet = InetAddressField(primary_key=True) ip = InetAddressField() login = models.CharField( max_length=260, null=True, blank=True, ) password = models.CharField( max_length=260, null=True, blank=True, ) user = models.ForeignKey( 'core.User', default=None, null=True, blank=True, on_delete=models.SET_NULL, ) time = models.DateTimeField( auto_now_add=True, db_index=True, null=True, blank=True, ) # success = models.BooleanField(default=False) objects = NetManager()
class Record(models.Model): """DMARC report record""" report = models.ForeignKey(Report, related_name='records', on_delete=models.CASCADE) source_ip = InetAddressField(store_prefix_length=False) recordcount = models.IntegerField() policyevaluated_disposition = models.CharField(max_length=10) policyevaluated_dkim = models.CharField(max_length=4) policyevaluated_spf = models.CharField(max_length=4) policyevaluated_reasontype = models.CharField(blank=True, max_length=75) policyevaluated_reasoncomment = models.CharField(blank=True, max_length=100) identifier_headerfrom = models.CharField(max_length=100) objects = NetManager() def __str__(self): return str(self.source_ip) class Meta: indexes = ( GistIndex( fields=('source_ip',), opclasses=('inet_ops',), name='dmarc_record_source_ip_idx' ), )
class BGPSession(ChangeLoggedModel, TaggableModel, PolicyMixin): """ Abstract class used to define common caracteristics of BGP sessions. A BGP session is always defined with the following fields: * an autonomous system, it can also be called a peer * an IP address used to establish the session * a plain text password * an encrypted version of the password if the user asked for encryption * a TTL for multihoping * an enabled or disabled status telling if the session should be administratively up or down * import routing policies to apply to prefixes sent by the remote device * export routing policies to apply to prefixed sent to the remote device * a BGP state giving the current operational state of session (it will remain to unkown if the is disabled) * a received prefix count (it will stay none if polling is disabled) * a advertised prefix count (it will stay none if polling is disabled) * a date and time record of the last established state of the session * comments that consist of plain text that can use the markdown format """ autonomous_system = models.ForeignKey("AutonomousSystem", on_delete=models.CASCADE) ip_address = InetAddressField(store_prefix_length=False, verbose_name="IP address") password = models.CharField(max_length=255, blank=True, null=True) encrypted_password = models.CharField(max_length=255, blank=True, null=True) multihop_ttl = TTLField( blank=True, default=1, verbose_name="Multihop TTL", help_text="Use a value greater than 1 for BGP multihop sessions", ) enabled = models.BooleanField(default=True) import_routing_policies = models.ManyToManyField( "RoutingPolicy", blank=True, related_name="%(class)s_import_routing_policies" ) export_routing_policies = models.ManyToManyField( "RoutingPolicy", blank=True, related_name="%(class)s_export_routing_policies" ) bgp_state = models.CharField( max_length=50, choices=BGPState.choices, blank=True, null=True ) service_reference = models.CharField( max_length=255, unique=True, blank=True, help_text="Optional internal service reference (auto-generated if left blank)", ) received_prefix_count = models.PositiveIntegerField(blank=True, default=0) advertised_prefix_count = models.PositiveIntegerField(blank=True, default=0) last_established_state = models.DateTimeField(blank=True, null=True) comments = models.TextField(blank=True) objects = NetManager() logger = logging.getLogger("peering.manager.peering") class Meta: abstract = True ordering = ["autonomous_system", "ip_address"] def __str__(self): return self.service_reference @property def ip_address_version(self): return ipaddress.ip_address(self.ip_address).version def export_policies(self): return self.export_routing_policies.all() def import_policies(self): return self.import_routing_policies.all() def poll(self): raise NotImplementedError def get_bgp_state_html(self): """ Return an HTML element based on the BGP state. """ if self.bgp_state == BGPState.IDLE: badge = "danger" elif self.bgp_state in [BGPState.CONNECT, BGPState.ACTIVE]: badge = "warning" elif self.bgp_state in [BGPState.OPENSENT, BGPState.OPENCONFIRM]: badge = "info" elif self.bgp_state == BGPState.ESTABLISHED: badge = "success" else: badge = "secondary" text = '<span class="badge badge-{}">{}</span>'.format( badge, self.get_bgp_state_display() or "Unknown" ) return mark_safe(text) def encrypt_password(self, commit=True): """ Sets the `encrypted_password` field if a crypto module is found for the given platform. The field will be set to `None` otherwise. Returns `True` if the encrypted password has been changed, `False` otherwise. """ try: router = getattr(self, "router") except AttributeError: router = getattr(self.ixp_connection, "router", None) if not router or not router.platform or not router.encrypt_passwords: return False if not self.password and self.encrypted_password: self.encrypted_password = "" if commit: self.save() return True if not self.encrypted_password: # If the password is not encrypted yet, do it self.encrypted_password = router.platform.encrypt_password(self.password) else: # Try to re-encrypt the encrypted password, if the resulting string is the # same it means the password matches the router platform algorithm is_up_to_date = self.encrypted_password == router.platform.encrypt_password( self.encrypted_password ) if not is_up_to_date: self.encrypted_password = router.platform.encrypt_password( self.password ) # Check if the encrypted password matches the clear one # Force re-encryption if there a difference if self.password != router.platform.decrypt_password(self.encrypted_password): self.encrypted_password = router.platform.encrypt_password(self.password) if commit: self.save() return True def generate_service_reference(self): """ Generate a unique service reference for a session from local ASN with 6 digit hex UUID. Example: IX9268-FD130FS/IX<asn>-<hex>S Example: D9268-4CD335S/D<asn>-<hex>S """ asn, prefix = "", "" # Find out ASN and prefix for the service ID based on the type of session if hasattr(self, "ixp_connection"): asn = str( self.ixp_connection.internet_exchange_point.local_autonomous_system.asn ) prefix = "IX" else: asn = str(self.local_autonomous_system.asn) prefix = "D" return f"{prefix}{asn}-{uuid.uuid4().hex[:6].upper()}S" def save(self, *args, **kwargs): """ Overrides default `save()` to set the service reference if left blank. """ if not self.service_reference: self.service_reference = self.generate_service_reference() return super().save(*args, **kwargs)
class NullCidrTestModel(Model): field = CidrAddressField(null=True) objects = NetManager() class Meta: db_table = 'nullcidr'
class Network(BaseModel): network = CidrAddressField(unique=True) description = models.TextField(blank=True) vlan = models.IntegerField(blank=True, null=True) dns_delegated = models.BooleanField(default=False) category = models.TextField(blank=True) location = models.TextField(blank=True) frozen = models.BooleanField(default=False) reserved = models.PositiveIntegerField(default=3) objects = NetManager() class Meta: db_table = 'network' ordering = ('network', ) def __str__(self): return str(self.network) def save(self, *args, **kwargs): if isinstance(self.network, str): network = ipaddress.ip_network(self.network) else: network = self.network if self.reserved > network.num_addresses: self.reserved = network.num_addresses super().save(*args, **kwargs) def get_reserved_ipaddresses(self): """ Returns a set with the reserved ip addresses for the network.""" network = self.network ret = set([network.network_address]) for i, ip in zip(range(self.reserved), network.hosts()): ret.add(ip) if isinstance(network, ipaddress.IPv4Network): ret.add(network.broadcast_address) return ret def get_excluded_ranges_start_end(self): excluded = [] for start_ip, end_ip in self.excluded_ranges.values_list( 'start_ip', 'end_ip'): start_ip = ipaddress.ip_address(start_ip) end_ip = ipaddress.ip_address(end_ip) excluded.append((start_ip, end_ip)) return excluded def get_unused_ipaddresses(self, max=MAX_UNUSED_LIST): """ Returns which ipaddresses on the network are unused. """ network_ips = [] used_or_reserved = self.used_addresses | self.get_reserved_ipaddresses( ) excluded = self.get_excluded_ranges_start_end() # Getting all available IPs for a ipv6 prefix can easily cause # the webserver to hang due to lots and lots of IPs. Instead limit # to the first MAX_UNUSED_LIST hosts. found = 0 ip = next(self.network.hosts()) while ip in self.network: if ip in used_or_reserved: ip += 1 continue was_excluded = False for start_ip, end_ip in excluded: if ip >= start_ip and ip <= end_ip: ip = end_ip + 1 was_excluded = True if was_excluded: continue network_ips.append(ip) found += 1 if found == max: break ip += 1 return set(network_ips) def __used(self, model): from_ip = str(self.network.network_address) to_ip = str(self.network.broadcast_address) return model.objects.filter(ipaddress__range=(from_ip, to_ip)) @staticmethod def __used_ips(qs): ips = qs.values_list('ipaddress', flat=True) return {ipaddress.ip_address(ip) for ip in ips} def _used_ipaddresses(self): return self.__used(Ipaddress) def _used_ptroverrides(self): return self.__used(PtrOverride) @property def used_ipaddresses(self): """ Returns the used Ipaddress objects on the network. """ return self.__used_ips(self._used_ipaddresses()) @property def used_ptroverrides(self): return self.__used_ips(self._used_ptroverrides()) @property def used_addresses(self): """ Returns which ipaddresses on the network are used. A combined usage of Ipaddress and PtrOverride. """ return self.used_ipaddresses | self.used_ptroverrides @property def unused_addresses(self): """ Returns which ipaddresses on the network are unused. """ return self.get_unused_ipaddresses() @property def unused_count(self): """ Returns the number of unused ipaddresses on the network. """ # start with the number of all adresses defined by the CIDR result = self.network.num_addresses # subtract excluded ranges for i in self.excluded_ranges.all(): result -= i.num_addresses() # subtract used and reserved addresses used_or_reserved = self.used_addresses | self.get_reserved_ipaddresses( ) result -= len(used_or_reserved) return result def get_first_unused(self): """ Return the first unused IP found, if any. """ a = self.get_unused_ipaddresses(1) if a: return str(next(iter(a))) return None def get_random_unused(self): """ Return a random unused IP, if any. """ unused = self.unused_addresses if unused: network = self.network if len( unused ) == MAX_UNUSED_LIST and network.num_addresses > MAX_UNUSED_LIST: # Attempt to use the entire address if encountering a network larger # than MAX_UNUSED_LIST. Typically an IPv6 network. network_address = int(network.network_address) broadcast_address = int(network.broadcast_address) used_or_reserved = self.used_addresses | self.get_reserved_ipaddresses( ) excluded = self.get_excluded_ranges_start_end() # Limit the number of attempts, as random might be really unlucky. for attempts in range(100): choice = random.randint(network_address, broadcast_address) if network.version == 6: randomip = ipaddress.IPv6Address(choice) else: randomip = ipaddress.IPv4Address(choice) if randomip in used_or_reserved: continue was_excluded = False for start_ip, end_ip in excluded: if randomip >= start_ip and randomip <= end_ip: was_excluded = True break if was_excluded: continue return str(randomip) return str(random.choice(tuple(unused))) return None
class NullInetTestModel(Model): field = InetAddressField(null=True) objects = NetManager() class Meta: db_table = 'nullinet'
class UniqueInetTestModel(Model): field = InetAddressField(unique=True) objects = NetManager() class Meta: db_table = 'uniqueinet'
class ReverseZone(BaseZone): name = DnsNameField(unique=True, validators=[validate_reverse_zone_name]) # network can not be blank, but it will allow full_clean() to pass, even if # the network is not set. Will anyway be overridden by update() and save(). network = CidrAddressField(unique=True, blank=True) objects = NetManager() class Meta: db_table = 'reverse_zone' def save(self, *args, **kwargs): self.network = get_network_from_zonename(self.name) super().save(*args, **kwargs) @staticmethod def get_zone_by_ip(ip): """Search and return a zone which contains an IP address.""" return ReverseZone.objects.filter(network__net_contains=ip).first() def _get_excluded_ranges(self): """ Get ranges which should not be exported in the reverse zone. These are addresses used by sub zones or delegations. Returned as a list of named tuples. """ excluded_ips = list() Range = namedtuple('Range', 'name from_ip to_ip') networks = list() for i in self.delegations.all(): networks.append(get_network_from_zonename(i.name)) for i in ReverseZone.objects.filter(name__endswith="." + self.name): networks.append(i.network) for network in networks: from_ip = str(network.network_address) to_ip = str(network.broadcast_address) excluded_ips.append( Range(name=str(network), from_ip=from_ip, to_ip=to_ip)) return excluded_ips def get_ipaddresses(self): """ Get all ipaddresses used in a reverse zone. Will return tuples of (ipaddress, ttl, hostname), sorted by ipaddress. """ network = self.network from_ip = str(network.network_address) to_ip = str(network.broadcast_address) ipaddresses = dict() override_ips = dict() excluded_ranges = self._get_excluded_ranges() for model, data in ( (Ipaddress, ipaddresses), (PtrOverride, override_ips), ): qs = model.objects.filter(ipaddress__range=(from_ip, to_ip)) for exclude in excluded_ranges: qs = qs.exclude(ipaddress__range=(exclude.from_ip, exclude.to_ip)) for ip, ttl, hostname in qs.values_list('ipaddress', 'host__ttl', 'host__name'): data[ip] = (ttl, hostname) # XXX: send signal/mail to hostmaster(?) about issues with multiple_ip_no_ptr count = defaultdict(int) for i in ipaddresses: if i not in override_ips: count[i] += 1 multiple_ip_no_ptr = {i: count[i] for i in count if count[i] > 1} ptr_done = set() result = [] def _add_to_result(ip, ttl, hostname): # Wildcards are not allowed in reverse zones. if "*" in hostname: return ttl = ttl or "" result.append((ipaddress.ip_address(ip), ttl, hostname)) # Use PtrOverrides when found, but only once. Also skip IPaddresses # which have been used multiple times, but lacks a PtrOverride. for ip, data in ipaddresses.items(): if ip in multiple_ip_no_ptr: continue if ip in override_ips: if ip not in ptr_done: ptr_done.add(ip) _add_to_result(ip, *override_ips[ip]) else: _add_to_result(ip, *data) # Add PtrOverrides which actually don't override anything, # but are only used as PTRs without any Ipaddress object creating # forward entries. for ptr, data in override_ips.items(): if ptr not in ptr_done: _add_to_result(ptr, *data) # Return sorted by IP return sorted(result, key=lambda i: i[0])
class ReverseZone(BaseZone): name = DnsNameField(unique=True, validators=[validate_reverse_zone_name]) # network can not be blank, but it will allow full_clean() to pass, even if # the network is not set. Will anyway be overridden by update() and save(). network = CidrAddressField(unique=True, blank=True) objects = NetManager() class Meta: db_table = 'reverse_zone' def save(self, *args, **kwargs): self.network = get_network_from_zonename(self.name) super().save(*args, **kwargs) @staticmethod def get_zone_by_ip(ip): """Search and return a zone which contains an IP address.""" return ReverseZone.objects.filter(network__net_contains=ip).first() def get_ipaddresses(self): network = self.network from_ip = str(network.network_address) to_ip = str(network.broadcast_address) ips = Ipaddress.objects.filter(ipaddress__range=(from_ip, to_ip)) ips = ips.select_related('host') override_ips = dict() ptrs = PtrOverride.objects.filter(ipaddress__range=(from_ip, to_ip)) ptrs = ptrs.select_related('host') for p in ptrs: override_ips[p.ipaddress] = p # XXX: send signal/mail to hostmaster(?) about issues with multiple_ip_no_ptr count = defaultdict(int) for i in ips: if i.ipaddress not in override_ips: count[i.ipaddress] += 1 multiple_ip_no_ptr = {i: count[i] for i in count if count[i] > 1} ptr_done = set() # Use PtrOverrides when found, but only once. Also skip IPaddresses # which have been used multiple times, but lacks a PtrOverride. result = [] def _add_to_result(item): ttl = item.host.ttl or "" result.append( (ipaddress.ip_address(item.ipaddress), ttl, item.host.name)) for i in ips: ip = i.ipaddress if ip in multiple_ip_no_ptr: continue if ip in override_ips: if ip not in ptr_done: ptr_done.add(ip) _add_to_result(override_ips[ip]) else: _add_to_result(i) # Add PtrOverrides which actually don't override anything, # but are only used as PTRs without any Ipaddress object creating # forward entries. for k, v in override_ips.items(): if k not in ptr_done: _add_to_result(v) # Return sorted by IP return sorted(result, key=lambda i: i[0])
class Network(models.Model): network = CidrAddressField(unique=True) description = models.TextField(blank=True) vlan = models.IntegerField(blank=True, null=True) dns_delegated = models.BooleanField(default=False) category = models.TextField(blank=True) location = models.TextField(blank=True) frozen = models.BooleanField(default=False) reserved = models.PositiveIntegerField(default=3) objects = NetManager() class Meta: db_table = 'network' ordering = ('network', ) def __str__(self): return str(self.network) def get_reserved_ipaddresses(self): """ Returns a set with the reserved ip addresses for the network.""" network = self.network ret = set([network.network_address]) for i, ip in zip(range(self.reserved), network.hosts()): ret.add(ip) if isinstance(network, ipaddress.IPv4Network): ret.add(network.broadcast_address) return ret def _get_used_ipaddresses(self): from_ip = str(self.network.network_address) to_ip = str(self.network.broadcast_address) #where_str = "ipaddress BETWEEN '{}' AND '{}'".format(from_ip, to_ip) #ips = Ipaddress.objects.extra(where=[where_str]) return Ipaddress.objects.filter(ipaddress__range=(from_ip, to_ip)) def get_used_ipaddresses(self): """ Returns the used ipaddress on the network. """ ips = self._get_used_ipaddresses() used = {ipaddress.ip_address(i.ipaddress) for i in ips} return used def get_used_ipaddress_count(self): """ Returns the number of used ipaddreses on the network. """ return self._get_used_ipaddresses().count() def get_unused_ipaddresses(self): """ Returns which ip-addresses on the network are unused. """ network_ips = [] if isinstance(self.network, ipaddress.IPv6Network): # Getting all availible IPs for a ipv6 prefix can easily cause # the webserver to hang due to lots and lots of IPs. Instead limit # to the first 4000 hosts. Should probably be configurable. for ip in self.network.hosts(): if len(network_ips) == 4000: break network_ips.append(ip) else: network_ips = self.network.hosts() reserved = self.get_reserved_ipaddresses() used = self.get_used_ipaddresses() return set(network_ips) - reserved - used def get_first_unused(self): """ Return the first unused IP found, if any. """ reserved = self.get_reserved_ipaddresses() used = self.get_used_ipaddresses() for ip in self.network.hosts(): if ip in reserved: continue if ip not in used: return str(ip) return None
class NetworkIXLAN(models.Model): asn = ASNField() name = models.CharField(max_length=255) ipaddr6 = InetAddressField( store_prefix_length=False, blank=True, null=True, validators=[AddressFamilyValidator(6)], ) ipaddr4 = InetAddressField( store_prefix_length=False, blank=True, null=True, validators=[AddressFamilyValidator(4)], ) is_rs_peer = models.BooleanField(default=False) ix_id = models.PositiveIntegerField() ixlan_id = models.PositiveIntegerField() objects = NetManager() logger = logging.getLogger("peering.manager.peeringdb") class Meta: ordering = ["asn", "ipaddr6", "ipaddr4"] verbose_name = "Network IX LAN" verbose_name_plural = "Network IX LANs" def save(self, *args, **kwargs): super().save(*args, **kwargs) # Ignore if we do not have any IP addresses if not self.ipaddr6 and not self.ipaddr4: self.logger.debug( "network ixlan with as%s and ixlan id %s ignored" ", no ipv6 and no ipv4", self.asn, self.ixlan_id, ) return # Trigger the build of a new PeerRecord or just ignore if it already # exists, assumes it exists # Note that there is not point of doing the same thing when a Network # or a NetworkIXLAN is deleted because it will automatically delete the # PeerRecord linked to it using the foreign key (with the CASCADE mode) network = None peer_record_exists = True try: # Try guessing the Network given its ASN network = Network.objects.get(asn=self.asn) # Try finding if the PeerRecord already exists PeerRecord.objects.get(network=network, network_ixlan=self) except Network.DoesNotExist: # The network does not exist, well not much to do self.logger.debug( "network with as%s does not exist, required for " "peer record creation", self.asn, ) except PeerRecord.DoesNotExist: # But if the exception is raised, it does not peer_record_exists = False # If the PeerRecord does not exist, create it if not peer_record_exists: PeerRecord.objects.create(network=network, network_ixlan=self) self.logger.debug( "peer record created with as%s and ixlan id %s", self.asn, self.ixlan_id ) else: self.logger.debug( "peer record with as%s and ixlan id %s exists", self.asn, self.ixlan_id ) def __str__(self): return "AS{} on {} - IPv6: {} - IPv4: {}".format( self.asn, self.name, self.ipaddr6, self.ipaddr4 )
class CidrTestModel(Model): field = CidrAddressField() objects = NetManager() class Meta: db_table = 'cidr'
class MACTestModel(Model): field = MACAddressField(null=True) objects = NetManager() class Meta: db_table = 'mac'
class InetTestModel(Model): field = InetAddressField() objects = NetManager() class Meta: db_table = 'inet'
class UniqueCidrTestModel(Model): field = CidrAddressField(unique=True) objects = NetManager() class Meta: db_table = 'uniquecidr'