Beispiel #1
0
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
Beispiel #2
0
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'
Beispiel #4
0
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')
Beispiel #5
0
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
Beispiel #6
0
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
Beispiel #7
0
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"
Beispiel #8
0
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)
Beispiel #9
0
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)
Beispiel #10
0
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)
Beispiel #11
0
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"
Beispiel #12
0
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
Beispiel #13
0
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)
Beispiel #14
0
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)
Beispiel #15
0
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', )
Beispiel #16
0
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()
Beispiel #17
0
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'
Beispiel #20
0
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'
Beispiel #23
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_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])
Beispiel #24
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])
Beispiel #25
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
Beispiel #26
0
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'