dnmgmt/api/views.py

225 lines
6.2 KiB
Python

# This file is part of dnmgmt, a number resource management system
# Licensed under GNU General Public License v3 or later
# Written by Sebastian Lohff (seba@someserver.de)
#from django.shortcuts import render
from django.http import JsonResponse
from django.core.exceptions import ValidationError
from django.contrib.auth.views import login_required
from django.db.models import Q
from whoisdb.models import ASBlock, ASNumber, InetNum
from domains.models import Domain, ReverseZone
from dnmgmt.settings import TLD_NAMESERVERS
from .dnshelper import checkDomain as helperCheckDomain
import ipaddress
@login_required
def asblockFreeAS(request):
ret = {
"success": False,
"errorMsg": None,
"number": -1,
}
try:
blockName = request.GET.get('block', None)
if not blockName:
raise ValidationError("No block given")
try:
mnts = request.user.maintainer_set.all()
block = ASBlock.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct().get(handle=blockName)
if block.asblock_set.count() > 0:
raise ValidationError("AS Block already has sub AS Blocks")
if block.asnumber_set.count() > 0:
num = block.asnumber_set.order_by("-number")[0].number + 1
if num > block.asEnd:
num = None
for n in range(block.asBegin, block.asEnd + 1):
try:
ASNumber.objects.get(number=n)
except ASNumber.DoesNotExist:
num = n
break
if not num:
raise ValidationError("No free AS Number in block")
ret["number"] = num
else:
ret["number"] = block.asBegin
except ASBlock.DoesNotExist:
raise ValidationError("Could not get AS Block")
ret["success"] = True
except ValidationError as e:
ret["errorMsg"] = e.message
return JsonResponse(ret)
@login_required
def freeSubnet(request):
ret = {
"success": False,
"errorMsg": None,
"network": None,
}
try:
parentRangeName = request.GET.get('parentRange', None)
if not parentRangeName:
raise ValidationError("No subnet given")
parentRange = None
try:
mnts = request.user.maintainer_set.all()
parentRange = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct().get(handle=parentRangeName)
except InetNum.DoesNotExist:
raise ValidationError("Parent range does not exist / is not maintained by you")
prefixLen = 0
try:
prefixLen = request.GET.get("prefixLen", None)
if not prefixLen:
if parentRange.protocol == InetNum.IPv4:
prefixLen = 27
else:
prefixLen = 60
prefixLen = int(prefixLen)
if prefixLen < 8 or \
(parentRange.protocol == InetNum.IPv4 and prefixLen > 32) or \
(parentRange.protocol == InetNum.IPv6 and prefixLen > 128):
raise ValidationError("Given prefix length is out of range")
except ValueError:
raise ValidationError("PrefixLen is not a number")
usableNet = None
# FIXME: use first biggest usable netblock...
#biggestNet = parentRange.inetnum_set.order_by("-address")
#if biggestNet
# candidateNet =
# and (biggestNet.getNetwork().broadcast_address.:
# try using next network in range
# ordering does not work, as order_by sorts alphabetically
# ==> the set is short, we can iterate through all. no sense in unpacking the SQL magic
#biggestNets = parentRange.inetnum_set.order_by("-address")
biggestNet = None
for ipRange in parentRange.inetnum_set.all():
if not biggestNet or ipRange.getNetwork() > biggestNet:
biggestNet = ipRange.getNetwork()
if biggestNet:
candidateNet = ipaddress.ip_network("%s/%s" % (biggestNet.broadcast_address + 1, biggestNet.prefixlen))
print("biggest net", biggestNet, "candidate", candidateNet)
if candidateNet.network_address in parentRange.getNetwork():
usableNet = candidateNet
# check if there are still networks left in range
if not usableNet:
# search for free network
nets = list(parentRange.getNetwork().subnets())
for subRange in parentRange.inetnum_set.all():
newNet = None
for net in nets:
if subRange.getNetwork().network_address in net:
newNet = net
if not newNet:
# critical error, we want a 500 here
raise ValueError("Subnet not in range")
nets.remove(newNet)
nets.extend(newNet.address_exclude(subRange.getNetwork()))
nets = sorted(nets)
for net in nets:
if net.prefixlen <= prefixLen:
usableNet = net
break
if not usableNet:
raise ValidationError("No space left in given range")
ret["network"] = "%s/%s" % (usableNet.network_address, prefixLen)
ret["success"] = True
except ValidationError as e:
ret["errorMsg"] = e.message
return JsonResponse(ret)
@login_required
def getSubnet(request):
ret = {
"success": False,
"errorMsg": None,
"network": None,
}
try:
netName = request.GET.get('net', None)
mnts = request.user.maintainer_set.all()
nets = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct()
net = nets.get(handle=netName)
ret["success"] = True
ret["network"] = net.prefix()
except InetNum.DoesNotExist:
ret["errorMsg"] = "Chosen network does not exist"
return JsonResponse(ret)
@login_required
def checkDomain(request):
ret = {
"success": False,
"errorMsg": None,
"domain": None,
"result": None,
}
try:
domainName = Domain.fixName(request.GET.get('domain', ''))
domain = Domain.objects.get(name=domainName)
#if not domain.canEdit(request.user):
# raise Domain.DoesNotExist()
ret["success"] = True
ret["domain"] = domain.name
# FIXME: change this if we ever have more than one...
ret["result"] = helperCheckDomain(domain.name, TLD_NAMESERVERS[0], domain.nameservers.all())
except Domain.DoesNotExist:
ret["errorMsg"] = "Domain does not exist"
return JsonResponse(ret)
@login_required
def checkRzone(request):
ret = {
"success": False,
"errorMsg": None,
"domain": None,
"result": None,
}
try:
rzonePk = int(request.GET.get('domain', ''))
rzone = ReverseZone.objects.get(pk=rzonePk)
#if not rzone.canEdit(request.user):
# raise ReverseZone.DoesNotExist()
ret["success"] = True
# FIXME: change this if we ever have more than one...
ret["result"] = helperCheckDomain(rzone.getZone(), TLD_NAMESERVERS[0], rzone.nameservers.all())
except (ReverseZone.DoesNotExist, ValueError):
ret["errorMsg"] = "ReverseZone does not exist"
return JsonResponse(ret)