193 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			193 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
# This file is part of dnmapper, an AS--level mapping tool
 | 
						|
# Licensed under GNU General Public License v3 or later
 | 
						|
# Written by Sebastian Lohff (seba@someserver.de)
 | 
						|
 | 
						|
from django.db import models
 | 
						|
from django.db.models import Q
 | 
						|
 | 
						|
 | 
						|
# Create your models here.
 | 
						|
class ConfigHost(models.Model):
 | 
						|
    CHECK_CHOICES = (
 | 
						|
        ('CMK', "Check MK"),
 | 
						|
        ('PLAIN', "Plain"),
 | 
						|
    )
 | 
						|
 | 
						|
    # asno, ip, check method,
 | 
						|
    name = models.CharField(max_length=50)
 | 
						|
    number = models.IntegerField()
 | 
						|
    ip = models.GenericIPAddressField()
 | 
						|
    checkMethod = models.CharField(max_length=4, choices=CHECK_CHOICES)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return "%s (%s / %s)" % (self.name, self.number, self.ip)
 | 
						|
 | 
						|
class CrawlRun(models.Model):
 | 
						|
    # time start, time end, 
 | 
						|
    startTime = models.DateTimeField()
 | 
						|
    endTime = models.DateTimeField(null=True, blank=True)
 | 
						|
 | 
						|
    hostsCrawled = models.ManyToManyField(ConfigHost, null=True, blank=True)
 | 
						|
 | 
						|
    asCount = models.IntegerField(default=0)
 | 
						|
    asOnlineCount = models.IntegerField(default=0)
 | 
						|
    asOfflineCount = models.IntegerField(default=0)
 | 
						|
    peeringCount = models.IntegerField(default=0)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return "Run %d - %s to %s" % (self.pk, self.startTime, self.endTime if self.endTime else "?")
 | 
						|
 | 
						|
    def countAS(self):
 | 
						|
        return self.asCount
 | 
						|
    def countASOnline(self):
 | 
						|
        return self.asOnlineCount
 | 
						|
    def countASOffline(self):
 | 
						|
        return self.asOfflineCount
 | 
						|
        #return self.as_set.filter(online=False).count()
 | 
						|
    def countPeerings(self):
 | 
						|
        return self.peeringCount
 | 
						|
        #return Peering.objects.filter(Q(as1__crawl=self)|Q(as2__crawl=self)).count()
 | 
						|
 | 
						|
class CrawlLog(models.Model):
 | 
						|
    INFO = 'INFO'
 | 
						|
    ERROR = 'ERROR'
 | 
						|
    DEBUG = 'DEBUG'
 | 
						|
    WARN = 'WARN'
 | 
						|
    SEVERITY = (
 | 
						|
        (INFO, 'info'),
 | 
						|
        (ERROR, 'error'),
 | 
						|
        (DEBUG, 'debug'),
 | 
						|
        (WARN, 'warning'),
 | 
						|
    )
 | 
						|
 | 
						|
    crawl = models.ForeignKey(CrawlRun)
 | 
						|
    host = models.ForeignKey(ConfigHost, null=True, blank=True, on_delete=models.SET_NULL)
 | 
						|
    logtime = models.DateTimeField(auto_now_add=True)
 | 
						|
    severity = models.CharField(max_length=10, choices=SEVERITY)
 | 
						|
    message = models.TextField()
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def log(crawl, msg, severity=None, host=None):
 | 
						|
        if not severity:
 | 
						|
            severity = CrawlLog.ERROR
 | 
						|
 | 
						|
        log = CrawlLog()
 | 
						|
        log.crawl = crawl
 | 
						|
        log.message = msg
 | 
						|
        log.severity = severity
 | 
						|
        log.host = host
 | 
						|
        log.save()
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        host = "host %s - " % self.host.name if self.host else ""
 | 
						|
        return "Log %s %s: %s%s" % (self.get_severity_display(), self.logtime, host, self.message)
 | 
						|
 | 
						|
class AS(models.Model):
 | 
						|
    # asno
 | 
						|
    crawl = models.ForeignKey(CrawlRun)
 | 
						|
    number = models.IntegerField(db_index=True)
 | 
						|
 | 
						|
    directlyCrawled = models.BooleanField(default=False)
 | 
						|
    online = models.BooleanField(default=True, db_index=True)
 | 
						|
    lastSeen = models.ForeignKey(CrawlRun, blank=True, null=True, default=None, related_name='as_lastseen')
 | 
						|
 | 
						|
    class Meta:
 | 
						|
        unique_together = (('crawl', 'number'),)
 | 
						|
        index_together = (
 | 
						|
            ('crawl', 'number'),
 | 
						|
        )
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return "AS %s (crawl %d)" % (self.number, self.crawl.pk)
 | 
						|
 | 
						|
    def setOnline(self):
 | 
						|
        if not self.online:
 | 
						|
            self.online = True
 | 
						|
            self.lastSeen = None
 | 
						|
            self.save()
 | 
						|
 | 
						|
    def getPeerings(self):
 | 
						|
        return Peering.objects.filter(Q(as1=self)|Q(as2=self))
 | 
						|
 | 
						|
    def getAnnouncedPrefixes(self):
 | 
						|
        return list(set(map(lambda _x: "%(ip)s/%(prefix)s" % _x, self.announcement_set.all().values('ip', 'prefix'))))
 | 
						|
 | 
						|
    def formatLastSeen(self):
 | 
						|
        if self.lastSeen:
 | 
						|
            return self.lastSeen.startTime.strftime("%d.%m.%Y %H:%I")
 | 
						|
 | 
						|
class BorderRouter(models.Model):
 | 
						|
    # as id, ip, check method, pingable, reachable
 | 
						|
    # unique: (crawl_id, asno, as id)
 | 
						|
    AS = models.ForeignKey(AS)
 | 
						|
    routerID = models.GenericIPAddressField()
 | 
						|
    
 | 
						|
    pingable = models.BooleanField(default=False)
 | 
						|
    reachable = models.BooleanField(default=False)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        p = "p" if self.pingable else "!p"
 | 
						|
        r = "r" if self.reachable else "!r"
 | 
						|
        return "Router %s (AS %s, %s%s)" % (self.routerID, self.AS.number, p, r)
 | 
						|
 | 
						|
class Announcement(models.Model):
 | 
						|
    router = models.ForeignKey(BorderRouter)
 | 
						|
 | 
						|
    ip = models.GenericIPAddressField()
 | 
						|
    prefix = models.IntegerField()
 | 
						|
 | 
						|
    # NOTE: increase length for longer pathes (currently supports a length of ~85)
 | 
						|
    ASPath = models.CharField(max_length=512)
 | 
						|
    nextHop = models.GenericIPAddressField()
 | 
						|
    originAS = models.ForeignKey(AS, null=True)
 | 
						|
    crawlAS = models.ForeignKey(AS, related_name='crawl_as', null=True)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return "%s/%s via %s (crawl %s)" % (self.ip, self.prefix, self.ASPath, self.router.AS.crawl.pk)
 | 
						|
 | 
						|
class Peering(models.Model):
 | 
						|
    DIRECT = 'direct'
 | 
						|
    PATH = 'path'
 | 
						|
 | 
						|
    ORIGIN = (
 | 
						|
        (PATH, 'BGP Path'),
 | 
						|
        (DIRECT, 'Direct Connection'),
 | 
						|
    )
 | 
						|
 | 
						|
    index_together = (
 | 
						|
        ('as1', 'as2'),
 | 
						|
    )
 | 
						|
 | 
						|
    as1 =  models.ForeignKey(AS, related_name='peering1')
 | 
						|
    as2 = models.ForeignKey(AS, related_name='peering2')
 | 
						|
    origin = models.CharField(max_length=10, choices=ORIGIN)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return "AS %s <--> AS %s (%s, crawl %s)" % (self.as1.number, self.as2.number, self.get_origin_display(), self.as1.crawl.pk)
 | 
						|
 | 
						|
    def containsAS(self, AS):
 | 
						|
        return AS in (self.as1, self.as2)
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def getPeering(as1, as2):
 | 
						|
        """ Find matching peering """
 | 
						|
        try:
 | 
						|
            return Peering.objects.get(as1=as1, as2=as2)
 | 
						|
        except Peering.DoesNotExist:
 | 
						|
            return Peering.objects.get(as1=as2, as2=as1)
 | 
						|
 | 
						|
class BorderRouterPair(models.Model):
 | 
						|
    peering = models.ForeignKey(Peering)
 | 
						|
    router1 = models.ForeignKey(BorderRouter, default=None, blank=True, null=True, related_name='routerpair1')
 | 
						|
    router2 = models.ForeignKey(BorderRouter, default=None, blank=True, null=True, related_name='routerpair2')
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return "%s <--> %s (crawl %d)" % (self.router1, self.router2, self.router1.AS.crawl.pk)
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def getPairing(peering, router1, router2):
 | 
						|
        try:
 | 
						|
            return BorderRouterPair.objects.get(peering=peering, router1=router1, router2=router2)
 | 
						|
        except BorderRouterPair.DoesNotExist:
 | 
						|
            return BorderRouterPair.objects.get(peering=peering, router1=router2, router2=router1)
 |