blob: fe78a9f4230d61f034ea4d8e81e2149498de35ad [file] [log] [blame]
#!/usr/bin/env python3
# SPDX-FileCopyrightText: © 2021 Open Networking Foundation <support@opennetworking.org>
# SPDX-License-Identifier: Apache-2.0
# service.py
import netaddr
from .container import ServiceInfoContainer
def getIPaddress(addressWithMask):
return str(netaddr.IPNetwork(addressWithMask).ip)
def dhcpSubnetConfigGenerator():
dhcpSubnetConfigs = list()
serviceInfoContainer = ServiceInfoContainer()
serviceInfoContainer.initialize()
for domainName, domain in serviceInfoContainer.all():
subnetConfig = {
"dns_search": [domainName],
"dns_servers": [domain["dnsServer"]["address"]],
"ntp_servers": [domain["ntpServer"]["address"]],
"tftpd_server": domain["dhcpServer"]["address"],
"range": domain["dhcprange"][0],
"subnet": domain["subnet"],
"routers": domain["router"],
"hosts": list(),
}
for address, host in domain["hosts"].items():
subnetConfig["hosts"].append(
{
"ip_addr": getIPaddress(address),
"mac_addr": host["macaddr"],
"name": host["hostname"],
}
)
subnetConfig["hosts"] = sorted(
subnetConfig["hosts"], key=lambda x: int(x["ip_addr"].split(".")[-1])
)
dhcpSubnetConfigs.append(subnetConfig)
return dhcpSubnetConfigs
def dnsFowardZoneConfigGenerator():
def getDomainNameByIP(ip_address):
"""
getDomainNameByIP will return the corresponding domain name of an IP address
In the ntpServer, dhcpServer, dnsServer we only have the IP addresses of them,
But we can use the dhcp subnet configuration to find the FQDN
"""
dhcpSubnetConfigs = dhcpSubnetConfigGenerator()
for domain in dhcpSubnetConfigs:
domainName = domain["dns_search"][0]
for host in domain["hosts"]:
if ip_address == host["ip_addr"]:
return f"{host['name']}.{domainName}."
return ""
dnsForwardZoneConfigs = dict()
serviceInfoContainer = ServiceInfoContainer()
serviceInfoContainer.initialize()
for domainName, domain in serviceInfoContainer.all():
forwardZoneConfig = {
"cname": dict(),
"a": dict(),
"ns": list(),
"srv": dict(),
"txt": dict(),
}
# Get the services set to this Tenant network
ntpServer = domain["ntpServer"] or None
dhcpServer = domain["dhcpServer"] or None
dnsServer = domain["dnsServer"] or None
# If service exists, set the FQDN to CNAME records
if ntpServer:
forwardZoneConfig["cname"]["ntp"] = getDomainNameByIP(ntpServer["address"])
if dhcpServer:
forwardZoneConfig["cname"]["tftp"] = getDomainNameByIP(
dhcpServer["address"]
)
if dnsServer:
forwardZoneConfig["cname"]["ns"] = getDomainNameByIP(dnsServer["address"])
forwardZoneConfig["ns"].append(getDomainNameByIP(dnsServer["address"]))
for address, host in domain["hosts"].items():
# Add exist IP address into dnsReverseZoneConfigs,
hostname = host["hostname"]
forwardZoneConfig["a"][hostname] = address
for address in netaddr.IPSet(domain["dhcprange"]):
# If address exists in ServiceInfoContainer's host dictionary,
# Use the pre-generated hostname as A record's name
hostname = "dhcp%03d" % address.words[-1]
forwardZoneConfig["a"][hostname] = str(address)
dnsForwardZoneConfigs[domainName] = forwardZoneConfig
return dnsForwardZoneConfigs
def dnsReverseZoneConfigGenerator():
def canonicalize_rfc1918_prefix(prefix):
"""
RFC1918 prefixes need to be expanded to their widest canonical range to
group all reverse lookup domains together for reverse DNS with NSD/Unbound.
"""
pnet = netaddr.IPNetwork(prefix)
(o1, o2, o3, o4) = pnet.network.words # Split ipv4 octets
cidr_plen = pnet.prefixlen
if o1 == 10:
o2 = o3 = o4 = 0
cidr_plen = 8
elif (o1 == 172 and 16 <= o2 <= 31) or (o1 == 192 and o2 == 168):
o3 = o4 = 0
cidr_plen = 16
return "%s/%d" % (".".join(map(str, [o1, o2, o3, o4])), cidr_plen)
serviceInfoContainer = ServiceInfoContainer()
serviceInfoContainer.initialize()
# dnsReverseZoneConfigs contains all reverse zone records.
dnsReverseZoneConfigs = dict()
widedomain = None
for domainName, domain in serviceInfoContainer.all():
# Expand network range to group all tenant domains
widedomain = widedomain or canonicalize_rfc1918_prefix(domain["subnet"])
# Create the basic structure of reverse zone config
# {"10.0.0.0/8": {"ns": list(), "ptr": dict()}}
dnsReverseZoneConfigs.setdefault(widedomain, dict())
dnsReverseZoneConfigs[widedomain].setdefault("ns", list())
dnsReverseZoneConfigs[widedomain].setdefault("ptr", dict())
# Get the DNS services set to this Tenant network
dnsServer = domain["dnsServer"]["name"] if domain["dnsServer"] else None
# If service exists, set the FQDN to CNAME records
if dnsServer:
dnsReverseZoneConfigs[widedomain]["ns"].append(f"{domainName}.{dnsServer}.")
for address, host in domain["hosts"].items():
# Add exist IP address into dnsReverseZoneConfigs,
hostname = host["hostname"]
dnsReverseZoneConfigs[widedomain]["ptr"][
address
] = f"{hostname}.{domainName}."
for address in netaddr.IPSet(domain["dhcprange"]):
# Add DHCP range IP address into dnsReverseZoneConfigs,
# Use the pre-generated hostname as A record's name
hostname = "dhcp%03d" % address.words[3]
dnsReverseZoneConfigs[widedomain]["ptr"][
str(address)
] = f"{hostname}.{domainName}."
dnsReverseZoneConfigs[widedomain]["ptr"] = dict(
sorted(
dnsReverseZoneConfigs[widedomain]["ptr"].items(),
key=lambda x: (int(x[0].split(".")[-2]), int(x[0].split(".")[-1])),
)
)
return dnsReverseZoneConfigs