bundlewrap/bundles/nftables/metadata.py

102 lines
3.2 KiB
Python
Raw Normal View History

2021-06-03 11:57:50 +00:00
from bundlewrap.exceptions import BundleError
defaults = {
'apt': {
'packages': {
'nftables': {},
},
},
'nftables': {
'blocked_v4': repo.libs.firewall.global_ip4_blocklist,
'blocked_v6': repo.libs.firewall.global_ip6_blocklist,
},
2021-06-03 11:57:50 +00:00
'pacman': {
'packages': {
'nftables': {},
# https://github.com/bundlewrap/bundlewrap/issues/688
# 'iptables': {
# 'installed': False,
# 'needed_by': {
# 'pkg_pacman:iptables-nft',
# },
# },
2021-06-03 11:57:50 +00:00
'iptables-nft': {
'needed_by': {
'pkg_pacman:nftables',
},
},
},
},
}
2024-10-26 14:25:54 +00:00
if not node.has_bundle('vmhost') and not node.has_bundle('docker-engine'):
2021-06-03 11:57:50 +00:00
# see comment in bundles/vmhost/items.py
defaults['apt']['packages']['iptables'] = {
'installed': False,
'needed_by': {
'pkg_apt:nftables',
},
}
@metadata_reactor.provides(
2023-09-24 18:59:58 +00:00
'nftables/input/99-port_rules',
2021-06-03 11:57:50 +00:00
)
def port_rules_to_nftables(metadata):
# Using this, bundles can simply set up port based rules. This
# reactor will then take care of converting those rules to actual
# nftables rules
ruleset = set()
# Plese note we do not set any defaults for ports. Bundles are
# expected to know themselves which default to use.
for portdef, targets in metadata.get('firewall/port_rules', {}).items():
if '/' in portdef:
port, proto = portdef.split('/', 2)
2023-09-24 18:59:58 +00:00
if proto not in ('tcp', 'udp'):
2021-06-03 11:57:50 +00:00
raise BundleError(f'firewall/port_rules: illegal identifier {portdef} in metadata for {node.name}')
else:
port = portdef
2023-09-24 18:59:58 +00:00
proto = None
2021-06-03 11:57:50 +00:00
for target in targets:
2023-09-24 18:59:58 +00:00
if (
(port == '*' and target == '*')
or (target == '*' and proto is None)
or (port != '*' and proto is None)
):
raise BundleError(f'firewall/port_rules: illegal combination of port, target and protocol: "{port}" "{target}" "{proto}"')
2021-06-03 11:57:50 +00:00
comment = f'comment "port_rules {target}"'
2021-06-03 11:57:50 +00:00
if port != '*':
if ':' in port:
parts = port.split(':')
2023-09-24 18:59:58 +00:00
port_str = f'{proto} dport {{ {parts[0]}-{parts[1]} }} '
2021-06-03 11:57:50 +00:00
else:
2023-09-24 18:59:58 +00:00
port_str = f'{proto} dport {port} '
elif proto is not None:
port_str = f'meta l4proto {proto} '
2021-06-03 11:57:50 +00:00
else:
2023-09-24 18:59:58 +00:00
port_str = ''
2021-06-03 11:57:50 +00:00
2023-09-24 18:59:58 +00:00
if target == '*':
ruleset.add(f'{port_str}accept {comment}')
2021-06-03 11:57:50 +00:00
else:
resolved = repo.libs.tools.resolve_identifier(repo, target, linklocal=True)
2021-06-03 11:57:50 +00:00
for address in resolved['ipv4']:
2023-09-24 18:59:58 +00:00
ruleset.add(f'{port_str}ip saddr {address} accept {comment}')
2021-06-03 11:57:50 +00:00
for address in resolved['ipv6']:
2023-09-24 18:59:58 +00:00
ruleset.add(f'{port_str}ip6 saddr {address} accept {comment}')
2021-06-03 11:57:50 +00:00
return {
'nftables': {
2023-09-24 18:59:58 +00:00
'input': {
2021-06-03 11:57:50 +00:00
# order does not matter here.
'99-port_rules': sorted(ruleset),
2021-06-03 11:57:50 +00:00
},
},
}