ADD import roles

This commit is contained in:
2024-09-15 09:42:20 +02:00
parent 4798dde38c
commit e6027e9078
36 changed files with 1129 additions and 0 deletions
@@ -0,0 +1,193 @@
import ipaddress
class FilterModule(object):
def filters(self):
return {
'generate_radvd': self.generate_radvd,
'generate_keepalived': self.generate_keepalived,
'generate_interfaces': self.generate_interfaces,
'generate_nftables': self.generate_nftables,
'generate_dhcpd': self.generate_dhcpd,
'generate_ospf': self.generate_ospf,
}
def generate_radvd(self, cluster_networks):
result = []
for net in cluster_networks:
if 'prefix' not in net:
continue
if 'dns' in net:
dns = net['dns']
else:
dns = ['2a00:1398::64:1', '2a00:1398::64:2']
radvd = {
'name': net['interface'],
'prefix': net['prefix'],
'source': 'fe80::1',
'dns': dns,
}
result.append(radvd)
return result
def generate_keepalived(self, cluster_networks):
result = []
for net in cluster_networks:
keepalived = {
'name': net['interface'],
'addresses': ['fe80::1/64'],
}
result.append(keepalived)
if 'prefix_v4' in net:
keepalived = {
'name': net['interface'] + '_v4',
'interface': net['interface'],
'addresses': [self.nth_addr_v4(net['prefix_v4'], 1)],
}
result.append(keepalived)
return result
def nth_addr(self, prefix: str, n:int) -> str:
network = ipaddress.IPv6Network(prefix)
# Check if n is within the valid range
if n >= network.num_addresses or n < 0:
raise ValueError(f"n must be between 0 and {network.num_addresses - 1}")
# Calculate the n-th address
nth_address = network.network_address + n
return str(nth_address) + '/' + str(network.prefixlen)
def nth_addr_v4(self, prefix: str, n:int, with_prefix: bool = True) -> str:
network = ipaddress.IPv4Network(prefix)
# Check if n is within the valid range
if n >= network.num_addresses or n < 0:
raise ValueError(f"n must be between 0 and {network.num_addresses - 1}")
# Calculate the n-th address
nth_address = network.network_address + n
if with_prefix:
return str(nth_address) + '/' + str(network.prefixlen)
else:
return str(nth_address)
def generate_interfaces(self, cluster_networks, addr_num):
result = []
for net in cluster_networks:
interface = {
'name': net['interface'],
'mac': net['mac'],
}
if 'prefix' in net:
inet6 = {
'addr': [self.nth_addr(net['prefix'], addr_num)],
'gateway': False,
'custom': False,
'routes': False,
}
interface['inet6'] = inet6
if 'prefix_v4' in net:
inet4 = {
'addr': [self.nth_addr_v4(net['prefix_v4'], addr_num)],
'gateway': False,
'custom': False,
'routes': False,
}
interface['inet'] = inet4
result.append(interface)
return result
def clean_port_range(self, port_range):
if ('{' not in port_range) and ('-' in port_range or ',' in port_range):
return '{{' + port_range + '}}'
return port_range
def generate_nftables(self, cluster_networks, upstream_interface):
result = []
nat_rules = []
default_policies = []
for net in cluster_networks:
if 'prefix' in net:
if net.get('firewall', None) is not None and net['firewall'].get('enabled', False) == True:
for rule in net['firewall'].get('rules', []):
if rule.get('dst', None) is None:
rule['dst'] = '%net'
nft_rule = 'oifname {} '.format(net['interface'])
if rule.get('src', '') != '':
nft_rule += 'ip6 saddr {} '.format(rule['src'].replace('%net', net['prefix']))
if rule.get('dst', '') != '':
nft_rule += 'ip6 daddr {} '.format(rule['dst'].replace('%net', net['prefix']))
if rule.get('sport', '') != '':
nft_rule += '{{proto}} sport {} '.format(self.clean_port_range(rule['sport']))
if rule.get('dport', '') != '':
nft_rule += '{{proto}} dport {} '.format(self.clean_port_range(rule['dport']))
nft_rule += rule['action']
for proto in rule.get('protocols', ['tcp', 'udp']):
result.append(nft_rule.format(proto=proto))
default_policies.append('oifname {} ip6 daddr {} {}'.format(net['interface'], net['prefix'], net['firewall']['policy']))
else:
default_policies.append('oifname {} ip6 daddr {} {}'.format(net['interface'], net['prefix'], 'accept'))
# NAT
if net.get('nat', None) is not None and net['nat'].get('enabled', False) == True:
if net['nat'].get('source', None) is not None and net.get('prefix_v4', None) is not None:
nat_rules.append('ip saddr {prefix} oif {dest_iface} snat to {source}'.format(prefix=net['prefix_v4'], dest_iface=upstream_interface, source=net['nat']['source']))
default_policies.append('oifname {} accept'.format(upstream_interface))
full_rules = "\n".join(result + default_policies)
full_nat = "\n".join(nat_rules)
ret = [
{
'name': 'cluster_router_bundle',
'rule': full_rules,
'chain': 'forward',
},
{
'name': 'cluster_router_bundle',
'rule': full_nat,
'chain': 'postrouting',
}
]
return ret
def is_v4(self, addr: str) -> bool:
try:
ipaddress.IPv4Address(addr)
return True
except ipaddress.AddressValueError:
return False
def generate_dhcpd(self, cluster_networks):
result = []
for net in cluster_networks:
if net.get('prefix_v4', None) is None:
continue
if net.get('dhcp', None) is None or net['dhcp'].get('enabled', False) == False:
continue
router = self.nth_addr_v4(net['prefix_v4'], 1, False)
subnet = self.nth_addr_v4(net['prefix_v4'], 0, False)
netmask = str(ipaddress.IPv4Network(net['prefix_v4']).netmask)
range_start = self.nth_addr_v4(net['prefix_v4'], net['dhcp'].get('range_start', 20), False)
range_end = self.nth_addr_v4(net['prefix_v4'], net['dhcp'].get('range_end', 150), False)
dhcpd = {
'interface': net['interface'],
'subnet': subnet,
'router': router,
'netmask': netmask,
'range_start': range_start,
'range_end': range_end,
}
dns = ', '.join(list(filter(lambda x: self.is_v4(x), net.get('dns', []))))
if len(dns) > 0:
dhcpd['dns'] = dns
result.append(dhcpd)
return result
def generate_ospf(self, cluster_networks):
result = []
for net in cluster_networks:
ospf = {
'name': net['interface'],
'stub': True,
}
result.append(ospf)
return result
+19
View File
@@ -0,0 +1,19 @@
---
- name: Generate radvd config
set_fact:
radvd_interfaces: "{{ cluster_networks | generate_radvd | union(radvd_interfaces | default([])) }}"
- name: Generate keepalived config
set_fact:
keepalived_interfaces: "{{ cluster_networks | generate_keepalived | union(keepalived_interfaces | default([])) }}"
- name: Generate interfaces config
set_fact:
net_interfaces: "{{ cluster_networks | generate_interfaces(cluster_v6_end) | union(net_interfaces | default([])) }}"
- name: Generate firewall config
set_fact:
nftables_rules: "{{ cluster_networks | generate_nftables(cluster_upstream_interface) | union(nftables_rules | default([])) }}"
- name: Generate dhcp config
set_fact:
isc_dhcp_networks: "{{ cluster_networks | generate_dhcpd | union(isc_dhcp_networks | default([])) }}"
# - name: Generate ospf config
# set_fact:
# bird_ospf_interfaces: "{{ cluster_networks | generate_ospf | union(bird_ospf_interfaces | default([])) }}"