97 lines
3 KiB
Python
97 lines
3 KiB
Python
|
from bundlewrap.exceptions import BundleError
|
||
|
|
||
|
defaults = {
|
||
|
'apt': {
|
||
|
'packages': {
|
||
|
'nftables': {},
|
||
|
},
|
||
|
},
|
||
|
'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/rules/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 {'udp'}:
|
||
|
raise BundleError(f'firewall/port_rules: illegal identifier {portdef} in metadata for {node.name}')
|
||
|
else:
|
||
|
port = portdef
|
||
|
proto = 'tcp'
|
||
|
|
||
|
for target in targets:
|
||
|
if port == '*' and target == '*':
|
||
|
raise BundleError('firewall/port_rules: setting both port and target to * is unsupported')
|
||
|
|
||
|
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}'
|
||
|
else:
|
||
|
port_str = f'meta l4proto {proto}'
|
||
|
|
||
|
if target in ('ipv4', 'ipv6'):
|
||
|
version_str = f'meta nfproto {target}'
|
||
|
else:
|
||
|
version_str = ''
|
||
|
|
||
|
if target in ('*', 'ipv4', 'ipv6'):
|
||
|
ruleset.add(f'inet filter input {version_str} {port_str} accept {comment}')
|
||
|
else:
|
||
|
resolved = repo.libs.tools.resolve_identifier(repo, target)
|
||
|
|
||
|
for address in resolved['ipv4']:
|
||
|
ruleset.add(f'inet filter input meta nfproto ipv4 {port_str} ip saddr {address} accept {comment}')
|
||
|
|
||
|
for address in resolved['ipv6']:
|
||
|
ruleset.add(f'inet filter input meta nfproto ipv6 {port_str} ip6 saddr {address} accept {comment}')
|
||
|
|
||
|
return {
|
||
|
'nftables': {
|
||
|
'rules': {
|
||
|
# order does not matter here.
|
||
|
'99-port_rules': sorted(ruleset),
|
||
|
},
|
||
|
},
|
||
|
}
|