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, }, 'pacman': { 'packages': { 'nftables': {}, # https://github.com/bundlewrap/bundlewrap/issues/688 # 'iptables': { # 'installed': False, # 'needed_by': { # 'pkg_pacman:iptables-nft', # }, # }, 'iptables-nft': { 'needed_by': { 'pkg_pacman:nftables', }, }, }, }, } if not node.has_bundle('vmhost'): # see comment in bundles/vmhost/items.py defaults['apt']['packages']['iptables'] = { 'installed': False, 'needed_by': { 'pkg_apt:nftables', }, } @metadata_reactor.provides( 'nftables/input/99-port_rules', ) 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) if proto not in ('tcp', 'udp'): raise BundleError(f'firewall/port_rules: illegal identifier {portdef} in metadata for {node.name}') else: port = portdef proto = None for target in targets: 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}"') comment = f'comment "port_rules {target}"' if port != '*': if ':' in port: parts = port.split(':') port_str = f'{proto} dport {{ {parts[0]}-{parts[1]} }} ' else: port_str = f'{proto} dport {port} ' elif proto is not None: port_str = f'meta l4proto {proto} ' else: port_str = '' if target == '*': ruleset.add(f'{port_str}accept {comment}') else: resolved = repo.libs.tools.resolve_identifier(repo, target, linklocal=True) for address in resolved['ipv4']: ruleset.add(f'{port_str}ip saddr {address} accept {comment}') for address in resolved['ipv6']: ruleset.add(f'{port_str}ip6 saddr {address} accept {comment}') return { 'nftables': { 'input': { # order does not matter here. '99-port_rules': sorted(ruleset), }, }, }