diff options
author | Daniil Baturin <daniil@vyos.io> | 2024-09-30 15:48:56 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-30 15:48:56 +0100 |
commit | eb55965347e53ac1dc336fe836b370a1f3e10a85 (patch) | |
tree | a076141622ec1e41133ef998076b21ce1b2abaac /src | |
parent | 0195aa1b0e99b6e886168c89fd2d018181918125 (diff) | |
parent | 4c3d037f036e84c77333a400b35bb1a628a1a118 (diff) | |
download | vyos-1x-eb55965347e53ac1dc336fe836b370a1f3e10a85.tar.gz vyos-1x-eb55965347e53ac1dc336fe836b370a1f3e10a85.zip |
Merge pull request #4024 from nicolas-fort/T6687
T6687: add fqdn support to nat rules.
Diffstat (limited to 'src')
-rwxr-xr-x | src/conf_mode/firewall.py | 21 | ||||
-rwxr-xr-x | src/conf_mode/nat.py | 20 | ||||
-rwxr-xr-x | src/helpers/vyos-domain-resolver.py | 107 | ||||
-rw-r--r-- | src/systemd/vyos-domain-resolver.service | 1 |
4 files changed, 93 insertions, 56 deletions
diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py index 5638a9668..ffbd915a2 100755 --- a/src/conf_mode/firewall.py +++ b/src/conf_mode/firewall.py @@ -36,11 +36,15 @@ from vyos.utils.process import cmd from vyos.utils.process import rc_cmd from vyos import ConfigError from vyos import airbag +from pathlib import Path from subprocess import run as subp_run airbag.enable() nftables_conf = '/run/nftables.conf' +domain_resolver_usage = '/run/use-vyos-domain-resolver-firewall' +domain_resolver_usage_nat = '/run/use-vyos-domain-resolver-nat' + sysctl_file = r'/run/sysctl/10-vyos-firewall.conf' valid_groups = [ @@ -128,7 +132,7 @@ def get_config(config=None): firewall['geoip_updated'] = geoip_updated(conf, firewall) - fqdn_config_parse(firewall) + fqdn_config_parse(firewall, 'firewall') set_dependents('conntrack', conf) @@ -570,12 +574,15 @@ def apply(firewall): call_dependents() - # T970 Enable a resolver (systemd daemon) that checks - # domain-group/fqdn addresses and update entries for domains by timeout - # If router loaded without internet connection or for synchronization - domain_action = 'stop' - if dict_search_args(firewall, 'group', 'domain_group') or firewall['ip_fqdn'] or firewall['ip6_fqdn']: - domain_action = 'restart' + ## DOMAIN RESOLVER + domain_action = 'restart' + if dict_search_args(firewall, 'group', 'domain_group') or firewall['ip_fqdn'].items() or firewall['ip6_fqdn'].items(): + text = f'# Automatically generated by firewall.py\nThis file indicates that vyos-domain-resolver service is used by the firewall.\n' + Path(domain_resolver_usage).write_text(text) + else: + Path(domain_resolver_usage).unlink(missing_ok=True) + if not Path('/run').glob('use-vyos-domain-resolver*'): + domain_action = 'stop' call(f'systemctl {domain_action} vyos-domain-resolver.service') if firewall['geoip_updated']: diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py index 39803fa02..98b2f3f29 100755 --- a/src/conf_mode/nat.py +++ b/src/conf_mode/nat.py @@ -26,10 +26,13 @@ from vyos.template import is_ip_network from vyos.utils.kernel import check_kmod from vyos.utils.dict import dict_search from vyos.utils.dict import dict_search_args +from vyos.utils.file import write_file from vyos.utils.process import cmd from vyos.utils.process import run +from vyos.utils.process import call from vyos.utils.network import is_addr_assigned from vyos.utils.network import interface_exists +from vyos.firewall import fqdn_config_parse from vyos import ConfigError from vyos import airbag @@ -39,6 +42,8 @@ k_mod = ['nft_nat', 'nft_chain_nat'] nftables_nat_config = '/run/nftables_nat.conf' nftables_static_nat_conf = '/run/nftables_static-nat-rules.nft' +domain_resolver_usage = '/run/use-vyos-domain-resolver-nat' +domain_resolver_usage_firewall = '/run/use-vyos-domain-resolver-firewall' valid_groups = [ 'address_group', @@ -71,6 +76,8 @@ def get_config(config=None): if 'dynamic_group' in nat['firewall_group']: del nat['firewall_group']['dynamic_group'] + fqdn_config_parse(nat, 'nat') + return nat def verify_rule(config, err_msg, groups_dict): @@ -251,6 +258,19 @@ def apply(nat): call_dependents() + # DOMAIN RESOLVER + if nat and 'deleted' not in nat: + domain_action = 'restart' + if nat['ip_fqdn'].items(): + text = f'# Automatically generated by nat.py\nThis file indicates that vyos-domain-resolver service is used by nat.\n' + write_file(domain_resolver_usage, text) + elif os.path.exists(domain_resolver_usage): + os.unlink(domain_resolver_usage) + if not os.path.exists(domain_resolver_usage_firewall): + # Firewall not using domain resolver + domain_action = 'stop' + call(f'systemctl {domain_action} vyos-domain-resolver.service') + return None if __name__ == '__main__': diff --git a/src/helpers/vyos-domain-resolver.py b/src/helpers/vyos-domain-resolver.py index 57cfcabd7..f5a1d9297 100755 --- a/src/helpers/vyos-domain-resolver.py +++ b/src/helpers/vyos-domain-resolver.py @@ -30,6 +30,8 @@ from vyos.xml_ref import get_defaults base = ['firewall'] timeout = 300 cache = False +base_firewall = ['firewall'] +base_nat = ['nat'] domain_state = {} @@ -46,25 +48,25 @@ ipv6_tables = { 'ip6 raw' } -def get_config(conf): - firewall = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True, +def get_config(conf, node): + node_config = conf.get_config_dict(node, key_mangling=('-', '_'), get_first_key=True, no_tag_node_value_mangle=True) - default_values = get_defaults(base, get_first_key=True) + default_values = get_defaults(node, get_first_key=True) - firewall = dict_merge(default_values, firewall) + node_config = dict_merge(default_values, node_config) global timeout, cache - if 'resolver_interval' in firewall: - timeout = int(firewall['resolver_interval']) + if 'resolver_interval' in node_config: + timeout = int(node_config['resolver_interval']) - if 'resolver_cache' in firewall: + if 'resolver_cache' in node_config: cache = True - fqdn_config_parse(firewall) + fqdn_config_parse(node_config, node[0]) - return firewall + return node_config def resolve(domains, ipv6=False): global domain_state @@ -108,55 +110,60 @@ def nft_valid_sets(): except: return [] -def update(firewall): +def update_fqdn(config, node): conf_lines = [] count = 0 - valid_sets = nft_valid_sets() - domain_groups = dict_search_args(firewall, 'group', 'domain_group') - if domain_groups: - for set_name, domain_config in domain_groups.items(): - if 'address' not in domain_config: - continue - - nft_set_name = f'D_{set_name}' - domains = domain_config['address'] - - ip_list = resolve(domains, ipv6=False) - for table in ipv4_tables: - if (table, nft_set_name) in valid_sets: - conf_lines += nft_output(table, nft_set_name, ip_list) - - ip6_list = resolve(domains, ipv6=True) - for table in ipv6_tables: - if (table, nft_set_name) in valid_sets: - conf_lines += nft_output(table, nft_set_name, ip6_list) + if node == 'firewall': + domain_groups = dict_search_args(config, 'group', 'domain_group') + if domain_groups: + for set_name, domain_config in domain_groups.items(): + if 'address' not in domain_config: + continue + nft_set_name = f'D_{set_name}' + domains = domain_config['address'] + + ip_list = resolve(domains, ipv6=False) + for table in ipv4_tables: + if (table, nft_set_name) in valid_sets: + conf_lines += nft_output(table, nft_set_name, ip_list) + ip6_list = resolve(domains, ipv6=True) + for table in ipv6_tables: + if (table, nft_set_name) in valid_sets: + conf_lines += nft_output(table, nft_set_name, ip6_list) + count += 1 + + for set_name, domain in config['ip_fqdn'].items(): + table = 'ip vyos_filter' + nft_set_name = f'FQDN_{set_name}' + ip_list = resolve([domain], ipv6=False) + if (table, nft_set_name) in valid_sets: + conf_lines += nft_output(table, nft_set_name, ip_list) count += 1 - for set_name, domain in firewall['ip_fqdn'].items(): - table = 'ip vyos_filter' - nft_set_name = f'FQDN_{set_name}' - - ip_list = resolve([domain], ipv6=False) - - if (table, nft_set_name) in valid_sets: - conf_lines += nft_output(table, nft_set_name, ip_list) - count += 1 - - for set_name, domain in firewall['ip6_fqdn'].items(): - table = 'ip6 vyos_filter' - nft_set_name = f'FQDN_{set_name}' + for set_name, domain in config['ip6_fqdn'].items(): + table = 'ip6 vyos_filter' + nft_set_name = f'FQDN_{set_name}' + ip_list = resolve([domain], ipv6=True) + if (table, nft_set_name) in valid_sets: + conf_lines += nft_output(table, nft_set_name, ip_list) + count += 1 - ip_list = resolve([domain], ipv6=True) - if (table, nft_set_name) in valid_sets: - conf_lines += nft_output(table, nft_set_name, ip_list) - count += 1 + else: + # It's NAT + for set_name, domain in config['ip_fqdn'].items(): + table = 'ip vyos_nat' + nft_set_name = f'FQDN_nat_{set_name}' + ip_list = resolve([domain], ipv6=False) + if (table, nft_set_name) in valid_sets: + conf_lines += nft_output(table, nft_set_name, ip_list) + count += 1 nft_conf_str = "\n".join(conf_lines) + "\n" code = run(f'nft --file -', input=nft_conf_str) - print(f'Updated {count} sets - result: {code}') + print(f'Updated {count} sets in {node} - result: {code}') if __name__ == '__main__': print(f'VyOS domain resolver') @@ -169,10 +176,12 @@ if __name__ == '__main__': time.sleep(1) conf = ConfigTreeQuery() - firewall = get_config(conf) + firewall = get_config(conf, base_firewall) + nat = get_config(conf, base_nat) print(f'interval: {timeout}s - cache: {cache}') while True: - update(firewall) + update_fqdn(firewall, 'firewall') + update_fqdn(nat, 'nat') time.sleep(timeout) diff --git a/src/systemd/vyos-domain-resolver.service b/src/systemd/vyos-domain-resolver.service index c56b51f0c..e63ae5e34 100644 --- a/src/systemd/vyos-domain-resolver.service +++ b/src/systemd/vyos-domain-resolver.service @@ -1,6 +1,7 @@ [Unit] Description=VyOS firewall domain resolver After=vyos-router.service +ConditionPathExistsGlob=/run/use-vyos-domain-resolver* [Service] Type=simple |