From 2ec023752bdd400835eb69a8f1f9d2873cef61fa Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Fri, 19 Jan 2024 21:01:52 +0100 Subject: firewall: T5729: T5681: T5217: backport subsystem from current branch This is a combined backport for all accumulated changes done to the firewall subsystem on the current branch. --- data/config-mode-dependencies/vyos-1x.json | 88 ++++--- data/templates/firewall/nftables-bridge.j2 | 8 +- data/templates/firewall/nftables-nat.j2 | 21 -- data/templates/firewall/nftables-nat66.j2 | 17 -- data/templates/firewall/nftables-offload.j2 | 2 +- data/templates/firewall/nftables-zone.j2 | 6 +- data/templates/firewall/nftables.j2 | 33 +-- data/vyos-firewall-init.conf | 82 +------ .../include/firewall/action-forward.xml.i | 10 +- .../include/firewall/action-l2.xml.i | 4 +- .../include/firewall/action.xml.i | 8 +- .../include/firewall/common-rule-bridge.xml.i | 7 +- .../include/firewall/common-rule-inet.xml.i | 11 +- .../include/firewall/common-rule-ipv4-raw.xml.i | 1 + .../include/firewall/default-action-bridge.xml.i | 6 +- .../include/firewall/default-action.xml.i | 2 +- .../include/firewall/firewall-mark.xml.i | 2 +- interface-definitions/include/firewall/log.xml.i | 3 +- .../include/firewall/match-interface.xml.i | 2 +- .../include/firewall/match-vlan.xml.i | 12 +- .../include/firewall/offload-target.xml.i | 2 +- interface-definitions/include/firewall/state.xml.i | 2 +- .../include/firewall/synproxy.xml.i | 40 ++++ .../include/firewall/tcp-flags.xml.i | 18 +- .../include/firewall/tcp-mss.xml.i | 25 ++ op-mode-definitions/show-log.xml.in | 264 +++++++++++++++++++-- python/vyos/firewall.py | 13 + python/vyos/template.py | 6 +- smoketest/scripts/cli/test_firewall.py | 49 +++- .../scripts/cli/test_system_flow-accounting.py | 2 +- src/conf_mode/firewall.py | 31 +-- src/conf_mode/load-balancing_wan.py | 5 + src/conf_mode/nat.py | 92 ++----- src/conf_mode/nat66.py | 45 +--- src/conf_mode/system_flow-accounting.py | 2 +- src/op_mode/firewall.py | 23 +- 36 files changed, 542 insertions(+), 402 deletions(-) create mode 100644 interface-definitions/include/firewall/synproxy.xml.i create mode 100644 interface-definitions/include/firewall/tcp-mss.xml.i diff --git a/data/config-mode-dependencies/vyos-1x.json b/data/config-mode-dependencies/vyos-1x.json index 81d86cf7e..4fd94d895 100644 --- a/data/config-mode-dependencies/vyos-1x.json +++ b/data/config-mode-dependencies/vyos-1x.json @@ -1,40 +1,52 @@ { - "firewall": { - "conntrack": ["system_conntrack"], - "group_resync": ["system_conntrack", "nat", "policy_route"] - }, - "interfaces_bonding": { - "ethernet": ["interfaces_ethernet"] - }, - "interfaces_bridge": { - "vxlan": ["interfaces_vxlan"] - }, - "pki": { - "ethernet": ["interfaces_ethernet"], - "openvpn": ["interfaces_openvpn"], - "https": ["service_https"], - "ipsec": ["vpn_ipsec"], - "openconnect": ["vpn_openconnect"], - "sstp": ["vpn_sstp"] - }, - "qos": { - "bonding": ["interfaces_bonding"], - "bridge": ["interfaces_bridge"], - "dummy": ["interfaces_dummy"], - "ethernet": ["interfaces_ethernet"], - "geneve": ["interfaces_geneve"], - "input": ["interfaces_input"], - "l2tpv3": ["interfaces_l2tpv3"], - "loopback": ["interfaces_loopback"], - "macsec": ["interfaces_macsec"], - "openvpn": ["interfaces_openvpn"], - "pppoe": ["interfaces_pppoe"], - "pseudo-ethernet": ["interfaces_pseudo-ethernet"], - "tunnel": ["interfaces_tunnel"], - "vti": ["interfaces_vti"], - "vxlan": ["interfaces_vxlan"], - "wireguard": ["interfaces_wireguard"], - "wireless": ["interfaces_wireless"], - "wwan": ["interfaces_wwan"] - } + "system_conntrack": { + "conntrack_sync": ["service_conntrack-sync"] + }, + "firewall": { + "conntrack": ["system_conntrack"], + "group_resync": ["system_conntrack", "nat", "policy_route"] + }, + "interfaces_bonding": { + "ethernet": ["interfaces_ethernet"] + }, + "interfaces_bridge": { + "vxlan": ["interfaces_vxlan"] + }, + "load_balancing_wan": { + "conntrack": ["system_conntrack"] + }, + "nat": { + "conntrack": ["system_conntrack"] + }, + "nat66": { + "conntrack": ["system_conntrack"] + }, + "pki": { + "ethernet": ["interfaces_ethernet"], + "openvpn": ["interfaces_openvpn"], + "https": ["service_https"], + "ipsec": ["vpn_ipsec"], + "openconnect": ["vpn_openconnect"], + "sstp": ["vpn_sstp"] + }, + "qos": { + "bonding": ["interfaces_bonding"], + "bridge": ["interfaces_bridge"], + "dummy": ["interfaces_dummy"], + "ethernet": ["interfaces_ethernet"], + "geneve": ["interfaces_geneve"], + "input": ["interfaces_input"], + "l2tpv3": ["interfaces_l2tpv3"], + "loopback": ["interfaces_loopback"], + "macsec": ["interfaces_macsec"], + "openvpn": ["interfaces_openvpn"], + "pppoe": ["interfaces_pppoe"], + "pseudo-ethernet": ["interfaces_pseudo-ethernet"], + "tunnel": ["interfaces_tunnel"], + "vti": ["interfaces_vti"], + "vxlan": ["interfaces_vxlan"], + "wireguard": ["interfaces_wireguard"], + "wireless": ["interfaces_wireless"], + "wwan": ["interfaces_wwan"] + } } diff --git a/data/templates/firewall/nftables-bridge.j2 b/data/templates/firewall/nftables-bridge.j2 index 1a4ad2ed9..dec027bf9 100644 --- a/data/templates/firewall/nftables-bridge.j2 +++ b/data/templates/firewall/nftables-bridge.j2 @@ -2,9 +2,8 @@ {% set ns = namespace(sets=[]) %} {% if bridge.forward is vyos_defined %} {% for prior, conf in bridge.forward.items() %} -{% set def_action = conf.default_action %} chain VYOS_FORWARD_{{ prior }} { - type filter hook forward priority {{ prior }}; policy {{ def_action }}; + type filter hook forward priority {{ prior }}; policy accept; {% if conf.rule is vyos_defined %} {% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %} {{ rule_conf | nft_rule('FWD', prior, rule_id, 'bri') }} @@ -13,6 +12,7 @@ {% endif %} {% endfor %} {% endif %} + {{ conf | nft_default_rule('FWD-filter', 'bri') }} } {% endfor %} {% endif %} @@ -28,8 +28,8 @@ {% endif %} {% endfor %} {% endif %} - {{ conf | nft_default_rule(name_text) }} + {{ conf | nft_default_rule(name_text, 'bri') }} } {% endfor %} {% endif %} -{% endmacro %} \ No newline at end of file +{% endmacro %} diff --git a/data/templates/firewall/nftables-nat.j2 b/data/templates/firewall/nftables-nat.j2 index dcf28da88..4254f6a0e 100644 --- a/data/templates/firewall/nftables-nat.j2 +++ b/data/templates/firewall/nftables-nat.j2 @@ -2,27 +2,6 @@ {% import 'firewall/nftables-defines.j2' as group_tmpl %} -{% if helper_functions is vyos_defined('remove') %} -{# NAT if going to be disabled - remove rules and targets from nftables #} -{% set base_command = 'delete rule ip raw' %} -{{ base_command }} PREROUTING handle {{ pre_ct_ignore }} -{{ base_command }} OUTPUT handle {{ out_ct_ignore }} -{{ base_command }} PREROUTING handle {{ pre_ct_conntrack }} -{{ base_command }} OUTPUT handle {{ out_ct_conntrack }} - -delete chain ip raw NAT_CONNTRACK - -{% elif helper_functions is vyos_defined('add') %} -{# NAT if enabled - add targets to nftables #} -add chain ip raw NAT_CONNTRACK -add rule ip raw NAT_CONNTRACK counter accept -{% set base_command = 'add rule ip raw' %} -{{ base_command }} PREROUTING position {{ pre_ct_ignore }} counter jump VYOS_CT_HELPER -{{ base_command }} OUTPUT position {{ out_ct_ignore }} counter jump VYOS_CT_HELPER -{{ base_command }} PREROUTING position {{ pre_ct_conntrack }} counter jump NAT_CONNTRACK -{{ base_command }} OUTPUT position {{ out_ct_conntrack }} counter jump NAT_CONNTRACK -{% endif %} - {% if first_install is not vyos_defined %} delete table ip vyos_nat {% endif %} diff --git a/data/templates/firewall/nftables-nat66.j2 b/data/templates/firewall/nftables-nat66.j2 index 27b3eec88..67eb2c109 100644 --- a/data/templates/firewall/nftables-nat66.j2 +++ b/data/templates/firewall/nftables-nat66.j2 @@ -1,22 +1,5 @@ #!/usr/sbin/nft -f -{% if helper_functions is vyos_defined('remove') %} -{# NAT if going to be disabled - remove rules and targets from nftables #} -{% set base_command = 'delete rule ip6 raw' %} -{{ base_command }} PREROUTING handle {{ pre_ct_conntrack }} -{{ base_command }} OUTPUT handle {{ out_ct_conntrack }} - -delete chain ip6 raw NAT_CONNTRACK - -{% elif helper_functions is vyos_defined('add') %} -{# NAT if enabled - add targets to nftables #} -add chain ip6 raw NAT_CONNTRACK -add rule ip6 raw NAT_CONNTRACK counter accept -{% set base_command = 'add rule ip6 raw' %} -{{ base_command }} PREROUTING position {{ pre_ct_conntrack }} counter jump NAT_CONNTRACK -{{ base_command }} OUTPUT position {{ out_ct_conntrack }} counter jump NAT_CONNTRACK -{% endif %} - {% if first_install is not vyos_defined %} delete table ip6 vyos_nat {% endif %} diff --git a/data/templates/firewall/nftables-offload.j2 b/data/templates/firewall/nftables-offload.j2 index 087fd141c..a893e05b2 100644 --- a/data/templates/firewall/nftables-offload.j2 +++ b/data/templates/firewall/nftables-offload.j2 @@ -6,4 +6,4 @@ {% endif %} counter } -{% endmacro %} \ No newline at end of file +{% endmacro %} diff --git a/data/templates/firewall/nftables-zone.j2 b/data/templates/firewall/nftables-zone.j2 index 506ad815e..e78725079 100644 --- a/data/templates/firewall/nftables-zone.j2 +++ b/data/templates/firewall/nftables-zone.j2 @@ -44,7 +44,7 @@ iifname { {{ zone[from_zone].interface | join(",") }} } counter return {% endfor %} {% endif %} - {{ zone_conf | nft_default_rule('zone_' + zone_name) }} + {{ zone_conf | nft_default_rule('zone_' + zone_name, family) }} } chain VZONE_{{ zone_name }}_OUT { oifname lo counter return @@ -54,7 +54,7 @@ oifname { {{ zone[from_zone].interface | join(",") }} } counter return {% endfor %} {% endif %} - {{ zone_conf | nft_default_rule('zone_' + zone_name) }} + {{ zone_conf | nft_default_rule('zone_' + zone_name, family) }} } {% else %} chain VZONE_{{ zone_name }} { @@ -70,7 +70,7 @@ {% endif %} {% endfor %} {% endif %} - {{ zone_conf | nft_default_rule('zone_' + zone_name) }} + {{ zone_conf | nft_default_rule('zone_' + zone_name, family) }} } {% endif %} {% endfor %} diff --git a/data/templates/firewall/nftables.j2 b/data/templates/firewall/nftables.j2 index 4851e3a05..833df3a67 100644 --- a/data/templates/firewall/nftables.j2 +++ b/data/templates/firewall/nftables.j2 @@ -5,17 +5,10 @@ {% import 'firewall/nftables-offload.j2' as offload_tmpl %} {% import 'firewall/nftables-zone.j2' as zone_tmpl %} -flush chain raw FW_CONNTRACK -flush chain ip6 raw FW_CONNTRACK - flush chain raw vyos_global_rpfilter flush chain ip6 raw vyos_global_rpfilter table raw { - chain FW_CONNTRACK { - {{ ipv4_conntrack_action }} - } - chain vyos_global_rpfilter { {% if global_options.source_validation is vyos_defined('loose') %} fib saddr oif 0 counter drop @@ -27,10 +20,6 @@ table raw { } table ip6 raw { - chain FW_CONNTRACK { - {{ ipv6_conntrack_action }} - } - chain vyos_global_rpfilter { {% if global_options.ipv6_source_validation is vyos_defined('loose') %} fib saddr oif 0 counter drop @@ -68,7 +57,7 @@ table ip vyos_filter { {% endif %} {% endfor %} {% endif %} - {{ conf | nft_default_rule('FWD-filter') }} + {{ conf | nft_default_rule('FWD-filter', 'ipv4') }} } {% endfor %} {% endif %} @@ -88,7 +77,7 @@ table ip vyos_filter { {% endif %} {% endfor %} {% endif %} - {{ conf | nft_default_rule('INP-filter') }} + {{ conf | nft_default_rule('INP-filter', 'ipv4') }} } {% endfor %} {% endif %} @@ -108,7 +97,7 @@ table ip vyos_filter { {% endif %} {% endfor %} {% endif %} - {{ conf | nft_default_rule('OUT-filter') }} + {{ conf | nft_default_rule('OUT-filter', 'ipv4') }} } {% endfor %} {% endif %} @@ -128,7 +117,7 @@ table ip vyos_filter { {% endif %} {% endfor %} {% endif %} - {{ conf | nft_default_rule('PRE-filter') }} + {{ conf | nft_default_rule('PRE-filter', 'ipv4') }} } {% endfor %} {% endif %} @@ -144,7 +133,7 @@ table ip vyos_filter { {% endif %} {% endfor %} {% endif %} - {{ conf | nft_default_rule(name_text) }} + {{ conf | nft_default_rule(name_text, 'ipv4') }} } {% endfor %} {% endif %} @@ -219,7 +208,7 @@ table ip6 vyos_filter { {% endif %} {% endfor %} {% endif %} - {{ conf | nft_default_rule('FWD-filter', ipv6=True) }} + {{ conf | nft_default_rule('FWD-filter', 'ipv6') }} } {% endfor %} {% endif %} @@ -239,7 +228,7 @@ table ip6 vyos_filter { {% endif %} {% endfor %} {% endif %} - {{ conf | nft_default_rule('INP-filter', ipv6=True) }} + {{ conf | nft_default_rule('INP-filter', 'ipv6') }} } {% endfor %} {% endif %} @@ -259,7 +248,7 @@ table ip6 vyos_filter { {% endif %} {% endfor %} {% endif %} - {{ conf | nft_default_rule('OUT-filter', ipv6=True) }} + {{ conf | nft_default_rule('OUT-filter', 'ipv6') }} } {% endfor %} {% endif %} @@ -280,7 +269,7 @@ table ip6 vyos_filter { {% endif %} {% endfor %} {% endif %} - {{ conf | nft_default_rule(name_text, ipv6=True) }} + {{ conf | nft_default_rule(name_text, 'ipv6') }} } {% endfor %} {% endif %} @@ -308,7 +297,6 @@ table ip6 vyos_filter { {% endif %} {% endif %} {{ group_tmpl.groups(group, True, True) }} - {% if zone is vyos_defined %} {{ zone_tmpl.zone_chains(zone, True, global_options.state_policy is vyos_defined) }} {% endif %} @@ -326,7 +314,6 @@ table ip6 vyos_filter { return } {% endif %} - } ## Bridge Firewall @@ -337,4 +324,4 @@ table bridge vyos_filter { {{ bridge_tmpl.bridge(bridge) }} {{ group_tmpl.groups(group, False, False) }} -} \ No newline at end of file +} diff --git a/data/vyos-firewall-init.conf b/data/vyos-firewall-init.conf index b0026fdf3..cd7d5011f 100644 --- a/data/vyos-firewall-init.conf +++ b/data/vyos-firewall-init.conf @@ -9,6 +9,7 @@ table ip nat { } table inet mangle { + # Used by system flow-accounting chain FORWARD { type filter hook forward priority -150; policy accept; } @@ -28,61 +29,9 @@ table raw { counter jump vyos_global_rpfilter } - chain PREROUTING { + # Used by system flow-accounting + chain VYOS_PREROUTING_HOOK { type filter hook prerouting priority -300; policy accept; - counter jump VYOS_CT_IGNORE - counter jump VYOS_CT_TIMEOUT - counter jump VYOS_CT_PREROUTING_HOOK - counter jump FW_CONNTRACK - notrack - } - - chain OUTPUT { - type filter hook output priority -300; policy accept; - counter jump VYOS_CT_IGNORE - counter jump VYOS_CT_TIMEOUT - counter jump VYOS_CT_OUTPUT_HOOK - counter jump FW_CONNTRACK - notrack - } - - ct helper rpc_tcp { - type "rpc" protocol tcp; - } - - ct helper rpc_udp { - type "rpc" protocol udp; - } - - ct helper tns_tcp { - type "tns" protocol tcp; - } - - chain VYOS_CT_HELPER { - ct helper set "rpc_tcp" tcp dport {111} return - ct helper set "rpc_udp" udp dport {111} return - ct helper set "tns_tcp" tcp dport {1521,1525,1536} return - return - } - - chain VYOS_CT_IGNORE { - return - } - - chain VYOS_CT_TIMEOUT { - return - } - - chain VYOS_CT_PREROUTING_HOOK { - return - } - - chain VYOS_CT_OUTPUT_HOOK { - return - } - - chain FW_CONNTRACK { - return } } @@ -100,29 +49,8 @@ table ip6 raw { counter jump vyos_global_rpfilter } - chain PREROUTING { + # Used by system flow-accounting + chain VYOS_PREROUTING_HOOK { type filter hook prerouting priority -300; policy accept; - counter jump VYOS_CT_PREROUTING_HOOK - counter jump FW_CONNTRACK - notrack - } - - chain OUTPUT { - type filter hook output priority -300; policy accept; - counter jump VYOS_CT_OUTPUT_HOOK - counter jump FW_CONNTRACK - notrack - } - - chain VYOS_CT_PREROUTING_HOOK { - return - } - - chain VYOS_CT_OUTPUT_HOOK { - return - } - - chain FW_CONNTRACK { - return } } diff --git a/interface-definitions/include/firewall/action-forward.xml.i b/interface-definitions/include/firewall/action-forward.xml.i index 87da72c97..4e59f3c6f 100644 --- a/interface-definitions/include/firewall/action-forward.xml.i +++ b/interface-definitions/include/firewall/action-forward.xml.i @@ -3,7 +3,7 @@ Rule action - accept continue jump reject return drop queue offload + accept continue jump reject return drop queue offload synproxy accept @@ -37,9 +37,13 @@ offload Offload packet via flowtable + + synproxy + Synproxy connections + - (accept|continue|jump|reject|return|drop|queue|offload) + (accept|continue|jump|reject|return|drop|queue|offload|synproxy) - \ No newline at end of file + diff --git a/interface-definitions/include/firewall/action-l2.xml.i b/interface-definitions/include/firewall/action-l2.xml.i index 43fd211b4..84af576c8 100644 --- a/interface-definitions/include/firewall/action-l2.xml.i +++ b/interface-definitions/include/firewall/action-l2.xml.i @@ -1,4 +1,4 @@ - + Rule action @@ -34,4 +34,4 @@ - \ No newline at end of file + diff --git a/interface-definitions/include/firewall/action.xml.i b/interface-definitions/include/firewall/action.xml.i index 5dd1bfaff..e1f0c6cb6 100644 --- a/interface-definitions/include/firewall/action.xml.i +++ b/interface-definitions/include/firewall/action.xml.i @@ -3,7 +3,7 @@ Rule action - accept continue jump reject return drop queue offload + accept continue jump reject return drop queue offload synproxy accept @@ -37,8 +37,12 @@ offload Offload packet via flowtable + + synproxy + Synproxy connections + - (accept|continue|jump|reject|return|drop|queue|offload) + (accept|continue|jump|reject|return|drop|queue|offload|synproxy) diff --git a/interface-definitions/include/firewall/common-rule-bridge.xml.i b/interface-definitions/include/firewall/common-rule-bridge.xml.i index dcdd970ac..6de770c79 100644 --- a/interface-definitions/include/firewall/common-rule-bridge.xml.i +++ b/interface-definitions/include/firewall/common-rule-bridge.xml.i @@ -9,7 +9,12 @@ #include -#include + + + Option to disable firewall rule + + + Set jump target. Action jump must be defined to use this setting diff --git a/interface-definitions/include/firewall/common-rule-inet.xml.i b/interface-definitions/include/firewall/common-rule-inet.xml.i index 3b5cb724d..6f56ecc85 100644 --- a/interface-definitions/include/firewall/common-rule-inet.xml.i +++ b/interface-definitions/include/firewall/common-rule-inet.xml.i @@ -7,7 +7,12 @@ #include #include #include -#include + + + Option to disable firewall rule + + + IP fragment match @@ -179,8 +184,10 @@ +#include #include #include +#include Time to match rule @@ -249,4 +256,4 @@ - \ No newline at end of file + diff --git a/interface-definitions/include/firewall/common-rule-ipv4-raw.xml.i b/interface-definitions/include/firewall/common-rule-ipv4-raw.xml.i index b253ee048..0d749aa27 100644 --- a/interface-definitions/include/firewall/common-rule-ipv4-raw.xml.i +++ b/interface-definitions/include/firewall/common-rule-ipv4-raw.xml.i @@ -260,6 +260,7 @@ #include +#include Time to match rule diff --git a/interface-definitions/include/firewall/default-action-bridge.xml.i b/interface-definitions/include/firewall/default-action-bridge.xml.i index 577165976..858c7aeeb 100644 --- a/interface-definitions/include/firewall/default-action-bridge.xml.i +++ b/interface-definitions/include/firewall/default-action-bridge.xml.i @@ -1,7 +1,7 @@ - + - Default action for rule-set + Default-action for rule-set drop jump return accept continue @@ -31,4 +31,4 @@ drop - \ No newline at end of file + diff --git a/interface-definitions/include/firewall/default-action.xml.i b/interface-definitions/include/firewall/default-action.xml.i index 6a49d800e..53a161495 100644 --- a/interface-definitions/include/firewall/default-action.xml.i +++ b/interface-definitions/include/firewall/default-action.xml.i @@ -1,7 +1,7 @@ - Default action for rule-set + Default-action for rule-set drop jump reject return accept continue diff --git a/interface-definitions/include/firewall/firewall-mark.xml.i b/interface-definitions/include/firewall/firewall-mark.xml.i index a4cee12d8..36a939ba3 100644 --- a/interface-definitions/include/firewall/firewall-mark.xml.i +++ b/interface-definitions/include/firewall/firewall-mark.xml.i @@ -23,4 +23,4 @@ - + \ No newline at end of file diff --git a/interface-definitions/include/firewall/log.xml.i b/interface-definitions/include/firewall/log.xml.i index 795ed77be..21548f3fb 100644 --- a/interface-definitions/include/firewall/log.xml.i +++ b/interface-definitions/include/firewall/log.xml.i @@ -4,4 +4,5 @@ Log packets hitting this rule - \ No newline at end of file + + diff --git a/interface-definitions/include/firewall/match-interface.xml.i b/interface-definitions/include/firewall/match-interface.xml.i index 9f720ab37..5da6f51fb 100644 --- a/interface-definitions/include/firewall/match-interface.xml.i +++ b/interface-definitions/include/firewall/match-interface.xml.i @@ -40,4 +40,4 @@ - + \ No newline at end of file diff --git a/interface-definitions/include/firewall/match-vlan.xml.i b/interface-definitions/include/firewall/match-vlan.xml.i index d0820f7d8..44ad02c99 100644 --- a/interface-definitions/include/firewall/match-vlan.xml.i +++ b/interface-definitions/include/firewall/match-vlan.xml.i @@ -6,14 +6,14 @@ - VLAN id + Vlan id u32:0-4096 - VLAN id + Vlan id <start-end> - VLAN id range to match + Vlan id range to match @@ -22,14 +22,14 @@ - VLAN priority(pcp) + Vlan priority(pcp) u32:0-7 - VLAN priority + Vlan priority <start-end> - VLAN priority range to match + Vlan priority range to match diff --git a/interface-definitions/include/firewall/offload-target.xml.i b/interface-definitions/include/firewall/offload-target.xml.i index b1ae39100..940ed8091 100644 --- a/interface-definitions/include/firewall/offload-target.xml.i +++ b/interface-definitions/include/firewall/offload-target.xml.i @@ -7,4 +7,4 @@ - \ No newline at end of file + diff --git a/interface-definitions/include/firewall/state.xml.i b/interface-definitions/include/firewall/state.xml.i index 47ce3c91d..dee9722e5 100644 --- a/interface-definitions/include/firewall/state.xml.i +++ b/interface-definitions/include/firewall/state.xml.i @@ -27,4 +27,4 @@ - \ No newline at end of file + diff --git a/interface-definitions/include/firewall/synproxy.xml.i b/interface-definitions/include/firewall/synproxy.xml.i new file mode 100644 index 000000000..a65126ea9 --- /dev/null +++ b/interface-definitions/include/firewall/synproxy.xml.i @@ -0,0 +1,40 @@ + + + + Synproxy options + + + + + TCP synproxy options + + + + + TCP Maximum segment size + + u32:501-65535 + Maximum segment size for synproxy connections + + + + + + + + + TCP window scale for synproxy connections + + u32:1-14 + TCP window scale + + + + + + + + + + + diff --git a/interface-definitions/include/firewall/tcp-flags.xml.i b/interface-definitions/include/firewall/tcp-flags.xml.i index e2ce7b9fd..36546c2e4 100644 --- a/interface-definitions/include/firewall/tcp-flags.xml.i +++ b/interface-definitions/include/firewall/tcp-flags.xml.i @@ -1,7 +1,7 @@ - TCP flags to match + TCP options to match @@ -114,22 +114,6 @@ - - - Maximum segment size (MSS) - - u32:1-16384 - Maximum segment size - - - <min>-<max> - TCP MSS range (use '-' as delimiter) - - - - - - diff --git a/interface-definitions/include/firewall/tcp-mss.xml.i b/interface-definitions/include/firewall/tcp-mss.xml.i new file mode 100644 index 000000000..dc49b4272 --- /dev/null +++ b/interface-definitions/include/firewall/tcp-mss.xml.i @@ -0,0 +1,25 @@ + + + + TCP options to match + + + + + Maximum segment size (MSS) + + u32:1-16384 + Maximum segment size + + + <min>-<max> + TCP MSS range (use '-' as delimiter) + + + + + + + + + diff --git a/op-mode-definitions/show-log.xml.in b/op-mode-definitions/show-log.xml.in index 432a21b59..f0525a6b8 100644 --- a/op-mode-definitions/show-log.xml.in +++ b/op-mode-definitions/show-log.xml.in @@ -139,47 +139,267 @@ Show log for Firewall + journalctl --no-hostname --boot -k | egrep "(ipv[46]|bri)-(FWD|INP|OUT|NAM)" - + - Show log for a specified firewall (IPv6) - - firewall ipv6-name - + Show firewall bridge log - cat $(printf "%s\n" /var/log/messages* | sort -nr ) | egrep "\[$5-([0-9]+|default)-[ADR]\]" + journalctl --no-hostname --boot -k | egrep "bri-(FWD|INP|OUT|NAM)" - + + + Show Bridge forward firewall log + + journalctl --no-hostname --boot -k | grep bri-FWD + + + + Show Bridge firewall forward filter + + journalctl --no-hostname --boot -k | grep bri-FWD-filter + + + + Show log for a rule in the specified firewall + + firewall bridge forward filter rule + + + journalctl --no-hostname --boot -k | egrep "\[bri-FWD-filter-$8-[ADRJC]\]" + + + + + + - Show log for a rule in the specified firewall + Show custom Bridge firewall log - firewall ipv6-name ${COMP_WORDS[4]} rule + firewall bridge name - cat $(printf "%s\n" /var/log/messages* | sort -nr) | grep -e "\[$5-$7-[ADR]\]" + journalctl --no-hostname --boot -k | grep bri-NAM-$6 + + + + Show log for a rule in the specified firewall + + firewall bridge name ${COMP_WORDS[5]} rule + + + journalctl --no-hostname --boot -k | egrep "\[bri-NAM-$6-$8-[ADRJC]\]" + + - - + + - Show log for a specified firewall (IPv4) - - firewall name - + Show firewall IPv4 log - cat $(printf "%s\n" /var/log/messages* | sort -nr ) | egrep "\[$5-([0-9]+|default)-[ADR]\]" + journalctl --no-hostname --boot -k | egrep "ipv4-(FWD|INP|OUT|NAM)" - + - Show log for a rule in the specified firewall + Show firewall IPv4 forward log + + journalctl --no-hostname --boot -k | grep ipv4-FWD + + + + Show firewall IPv4 forward filter log + + journalctl --no-hostname --boot -k | grep ipv4-FWD-filter + + + + Show log for a rule in the specified firewall + + firewall ipv4 forward filter rule + + + journalctl --no-hostname --boot -k | egrep "\[ipv4-FWD-filter-$8-[ADRJC]\]" + + + + + + + + Show firewall IPv4 input log + + journalctl --no-hostname --boot -k | grep ipv4-INP + + + + Show firewall IPv4 input filter log + + journalctl --no-hostname --boot -k | grep ipv4-INP-filter + + + + Show log for a rule in the specified firewall + + firewall ipv4 input filter rule + + + journalctl --no-hostname --boot -k | egrep "\[ipv4-INP-filter-$8-[ADRJC]\]" + + + + + + + + Show custom IPv4 firewall log - firewall name ${COMP_WORDS[4]} rule + firewall ipv4 name - cat $(printf "%s\n" /var/log/messages* | sort -nr) | egrep "\[$5-$7-[ADR]\]" + journalctl --no-hostname --boot -k | grep ipv4-NAM-$6 + + + + Show log for a rule in the specified firewall + + firewall ipv4 name ${COMP_WORDS[5]} rule + + + journalctl --no-hostname --boot -k | egrep "\[ipv4-NAM-$6-$8-[ADRJC]\]" + + + + + Show firewall IPv4 output log + + journalctl --no-hostname --boot -k | grep ipv4-OUT + + + + Show firewall IPv4 output filter log + + journalctl --no-hostname --boot -k | grep ipv4-OUT-filter + + + + Show log for a rule in the specified firewall + + firewall ipv4 output filter rule + + + journalctl --no-hostname --boot -k | egrep "\[ipv4-OUT-filter-$8-[ADRJC]\]" + + + + + - + + + + Show firewall IPv6 log + + journalctl --no-hostname --boot -k | egrep "ipv6-(FWD|INP|OUT|NAM)" + + + + Show firewall IPv6 forward log + + journalctl --no-hostname --boot -k | grep ipv6-FWD + + + + Show firewall IPv6 forward filter log + + journalctl --no-hostname --boot -k | grep ipv6-FWD-filter + + + + Show log for a rule in the specified firewall + + firewall ipv6 forward filter rule + + + journalctl --no-hostname --boot -k | egrep "\[ipv6-FWD-filter-$8-[ADRJC]\]" + + + + + + + + Show firewall IPv6 input log + + journalctl --no-hostname --boot -k | grep ipv6-INP + + + + Show firewall IPv6 input filter log + + journalctl --no-hostname --boot -k | grep ipv6-INP-filter + + + + Show log for a rule in the specified firewall + + firewall ipv6 input filter rule + + + journalctl --no-hostname --boot -k | egrep "\[ipv6-INP-filter-$8-[ADRJC]\]" + + + + + + + + Show custom IPv6 firewall log + + firewall ipv6 name + + + journalctl --no-hostname --boot -k | grep ipv6-NAM-$6 + + + + Show log for a rule in the specified firewall + + firewall ipv6 name ${COMP_WORDS[5]} rule + + + journalctl --no-hostname --boot -k | egrep "\[ipv6-NAM-$6-$8-[ADRJC]\]" + + + + + + Show firewall IPv6 output log + + journalctl --no-hostname --boot -k | grep ipv6-OUT + + + + Show firewall IPv6 output filter log + + journalctl --no-hostname --boot -k | grep ipv6-OUT-filter + + + + Show log for a rule in the specified firewall + + firewall ipv6 output filter rule + + + journalctl --no-hostname --boot -k | egrep "\[ipv6-OUT-filter-$8-[ADRJC]\]" + + + + + + + diff --git a/python/vyos/firewall.py b/python/vyos/firewall.py index 4fc1abb15..a2622fa00 100644 --- a/python/vyos/firewall.py +++ b/python/vyos/firewall.py @@ -87,6 +87,7 @@ def nft_action(vyos_action): def parse_rule(rule_conf, hook, fw_name, rule_id, ip_name): output = [] + if ip_name == 'ip6': def_suffix = '6' family = 'ipv6' @@ -261,6 +262,9 @@ def parse_rule(rule_conf, hook, fw_name, rule_id, ip_name): output.append(f'{proto} {prefix}port {operator} @P_{group_name}') + if dict_search_args(rule_conf, 'action') == 'synproxy': + output.append('ct state invalid,untracked') + if 'hop_limit' in rule_conf: operators = {'eq': '==', 'gt': '>', 'lt': '<'} for op, operator in operators.items(): @@ -440,6 +444,15 @@ def parse_rule(rule_conf, hook, fw_name, rule_id, ip_name): queue_opts = ','.join(rule_conf['queue_options']) output.append(f'{queue_opts}') + # Synproxy + if 'synproxy' in rule_conf: + synproxy_mss = dict_search_args(rule_conf, 'synproxy', 'tcp', 'mss') + if synproxy_mss: + output.append(f'mss {synproxy_mss}') + synproxy_ws = dict_search_args(rule_conf, 'synproxy', 'tcp', 'window_scale') + if synproxy_ws: + output.append(f'wscale {synproxy_ws} timestamp sack-perm') + else: output.append('return') diff --git a/python/vyos/template.py b/python/vyos/template.py index 4b6dca254..d1b3e8fa8 100644 --- a/python/vyos/template.py +++ b/python/vyos/template.py @@ -574,10 +574,10 @@ def nft_rule(rule_conf, fw_hook, fw_name, rule_id, ip_name='ip'): return parse_rule(rule_conf, fw_hook, fw_name, rule_id, ip_name) @register_filter('nft_default_rule') -def nft_default_rule(fw_conf, fw_name, ipv6=False): +def nft_default_rule(fw_conf, fw_name, family): output = ['counter'] default_action = fw_conf['default_action'] - family = 'ipv6' if ipv6 else 'ipv4' + #family = 'ipv6' if ipv6 else 'ipv4' if 'default_log' in fw_conf: action_suffix = default_action[:1].upper() @@ -587,7 +587,7 @@ def nft_default_rule(fw_conf, fw_name, ipv6=False): output.append(f'{default_action}') if 'default_jump_target' in fw_conf: target = fw_conf['default_jump_target'] - def_suffix = '6' if ipv6 else '' + def_suffix = '6' if family == 'ipv6' else '' output.append(f'NAME{def_suffix}_{target}') output.append(f'comment "{fw_name} default-action {default_action}"') diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py index 353fa0b2b..72fbdb37d 100755 --- a/smoketest/scripts/cli/test_firewall.py +++ b/smoketest/scripts/cli/test_firewall.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021-2022 VyOS maintainers and contributors +# Copyright (C) 2021-2023 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -277,6 +277,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase): ['type filter hook output priority filter; policy accept;'], ['meta l4proto gre', f'oifname != "{interface}"', 'drop'], ['meta l4proto icmp', f'ct mark {mark_hex}', 'return'], + ['log prefix "[ipv4-OUT-filter-default-D]"','OUT-filter default-action drop', 'drop'], ['chain NAME_smoketest'], ['saddr 172.16.20.10', 'daddr 172.16.10.10', 'log prefix "[ipv4-NAM-smoketest-1-A]" log level debug', 'ip ttl 15', 'accept'], ['tcp flags syn / syn,ack', 'tcp dport 8888', 'log prefix "[ipv4-NAM-smoketest-2-R]" log level err', 'ip ttl > 102', 'reject'], @@ -346,6 +347,31 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase): self.verify_nftables(nftables_search, 'ip vyos_filter') + def test_ipv4_synproxy(self): + tcp_mss = '1460' + tcp_wscale = '7' + dport = '22' + + self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '10', 'action', 'drop']) + self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '10', 'protocol', 'tcp']) + self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '10', 'destination', 'port', dport]) + self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '10', 'synproxy', 'tcp', 'mss', tcp_mss]) + self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '10', 'synproxy', 'tcp', 'window-scale', tcp_wscale]) + + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '10', 'action', 'synproxy']) + + self.cli_commit() + + nftables_search = [ + [f'tcp dport {dport} ct state invalid,untracked', f'synproxy mss {tcp_mss} wscale {tcp_wscale} timestamp sack-perm'] + ] + + self.verify_nftables(nftables_search, 'ip vyos_filter') + + def test_ipv4_mask(self): name = 'smoketest-mask' interface = 'eth0' @@ -463,6 +489,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase): self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'default-action', 'accept']) self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'rule', '1', 'source', 'address', '2001:db8::/64']) + self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'rule', '1', 'mark', '!6655-7766']) self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'rule', '1', 'action', 'jump']) self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'rule', '1', 'jump-target', name]) @@ -474,7 +501,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase): ['ip6 length 1-1999', 'ip6 length != 60000-65535', 'ip6 dscp 0x04-0x0e', 'ip6 dscp != 0x1f-0x23', 'accept'], ['chain VYOS_IPV6_INPUT_filter'], ['type filter hook input priority filter; policy accept;'], - ['ip6 saddr 2001:db8::/64', f'jump NAME6_{name}'], + ['ip6 saddr 2001:db8::/64', 'meta mark != 0x000019ff-0x00001e56', f'jump NAME6_{name}'], [f'chain NAME6_{name}'], ['ip6 length { 65, 513, 1025 }', 'ip6 dscp { af21, 0x35 }', 'accept'], [f'log prefix "[ipv6-{name}-default-D]"', 'drop'] @@ -558,8 +585,8 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase): self.verify_nftables(nftables_search, 'ip vyos_filter') # Check conntrack - self.verify_nftables_chain([['accept']], 'raw', 'FW_CONNTRACK') - self.verify_nftables_chain([['return']], 'ip6 raw', 'FW_CONNTRACK') + self.verify_nftables_chain([['accept']], 'ip vyos_conntrack', 'FW_CONNTRACK') + self.verify_nftables_chain([['return']], 'ip6 vyos_conntrack', 'FW_CONNTRACK') def test_bridge_basic_rules(self): name = 'smoketest' @@ -588,11 +615,13 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase): nftables_search = [ ['chain VYOS_FORWARD_filter'], - ['type filter hook forward priority filter; policy drop;'], + ['type filter hook forward priority filter; policy accept;'], [f'vlan id {vlan_id}', 'accept'], [f'vlan pcp {vlan_prior}', f'jump NAME_{name}'], + ['log prefix "[bri-FWD-filter-default-D]"', 'drop', 'FWD-filter default-action drop'], [f'chain NAME_{name}'], - [f'ether saddr {mac_address}', f'iifname "{interface_in}"', f'log prefix "[bri-NAM-{name}-1-A]" log level crit', 'accept'] + [f'ether saddr {mac_address}', f'iifname "{interface_in}"', f'log prefix "[bri-NAM-{name}-1-A]" log level crit', 'accept'], + ['accept', f'{name} default-action accept'] ] self.verify_nftables(nftables_search, 'bridge vyos_filter') @@ -737,8 +766,8 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase): self.verify_nftables(nftables_search, 'ip6 vyos_filter') # Check conntrack - #self.verify_nftables_chain([['accept']], 'ip vyos_conntrack', 'FW_CONNTRACK') - #self.verify_nftables_chain([['accept']], 'ip6 vyos_conntrack', 'FW_CONNTRACK') + self.verify_nftables_chain([['accept']], 'ip vyos_conntrack', 'FW_CONNTRACK') + self.verify_nftables_chain([['accept']], 'ip6 vyos_conntrack', 'FW_CONNTRACK') def test_zone_flow_offload(self): self.cli_set(['firewall', 'flowtable', 'smoketest', 'interface', 'eth0']) @@ -773,8 +802,8 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase): self.verify_nftables(nftables_search, 'ip6 vyos_filter') # Check conntrack - #self.verify_nftables_chain([['accept']], 'ip vyos_conntrack', 'FW_CONNTRACK') - #self.verify_nftables_chain([['accept']], 'ip6 vyos_conntrack', 'FW_CONNTRACK') + self.verify_nftables_chain([['accept']], 'ip vyos_conntrack', 'FW_CONNTRACK') + self.verify_nftables_chain([['accept']], 'ip6 vyos_conntrack', 'FW_CONNTRACK') if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_system_flow-accounting.py b/smoketest/scripts/cli/test_system_flow-accounting.py index d55ea616e..6c761579b 100755 --- a/smoketest/scripts/cli/test_system_flow-accounting.py +++ b/smoketest/scripts/cli/test_system_flow-accounting.py @@ -67,7 +67,7 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase): self.cli_commit() # verify configuration - nftables_output = cmd('sudo nft list chain raw VYOS_CT_PREROUTING_HOOK').splitlines() + nftables_output = cmd('sudo nft list chain raw VYOS_PREROUTING_HOOK').splitlines() for interface in Section.interfaces('ethernet'): rule_found = False ifname_search = f'iifname "{interface}"' diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py index ee19555c4..acb7dfa41 100755 --- a/src/conf_mode/firewall.py +++ b/src/conf_mode/firewall.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021-2022 VyOS maintainers and contributors +# Copyright (C) 2021-2023 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -39,6 +39,7 @@ from vyos.utils.process import process_named_running from vyos.utils.process import rc_cmd from vyos import ConfigError from vyos import airbag + airbag.enable() nftables_conf = '/run/nftables.conf' @@ -98,7 +99,7 @@ def geoip_updated(conf, firewall): elif (path[0] == 'ipv6'): set_name = f'GEOIP_CC6_{path[1]}_{path[2]}_{path[4]}' out['ipv6_name'].append(set_name) - + updated = True if 'delete' in node_diff: @@ -138,6 +139,8 @@ def get_config(config=None): fqdn_config_parse(firewall) + set_dependents('conntrack', conf) + return firewall def verify_rule(firewall, rule_conf, ipv6): @@ -167,6 +170,16 @@ def verify_rule(firewall, rule_conf, ipv6): if not dict_search_args(firewall, 'flowtable', offload_target): raise ConfigError(f'Invalid offload-target. Flowtable "{offload_target}" does not exist on the system') + if rule_conf['action'] != 'synproxy' and 'synproxy' in rule_conf: + raise ConfigError('"synproxy" option allowed only for action synproxy') + if rule_conf['action'] == 'synproxy': + if 'state' in rule_conf: + raise ConfigError('For action "synproxy" state cannot be defined') + if not rule_conf.get('synproxy', {}).get('tcp'): + raise ConfigError('synproxy TCP MSS is not defined') + if rule_conf.get('protocol', {}) != 'tcp': + raise ConfigError('For action "synproxy" the protocol must be set to TCP') + if 'queue_options' in rule_conf: if 'queue' not in rule_conf['action']: raise ConfigError('queue-options defined, but action queue needed and it is not defined') @@ -434,17 +447,6 @@ def generate(firewall): if local_zone in zone_conf['from']: local_zone_conf['from_local'][zone] = zone_conf['from'][local_zone] - # Determine if conntrack is needed - firewall['ipv4_conntrack_action'] = 'return' - firewall['ipv6_conntrack_action'] = 'return' - - for rules, path in dict_search_recursive(firewall, 'rule'): - if any(('state' in rule_conf or 'connection_status' in rule_conf) for rule_conf in rules.values()): - if path[0] == 'ipv4': - firewall['ipv4_conntrack_action'] = 'accept' - elif path[0] == 'ipv6': - firewall['ipv6_conntrack_action'] = 'accept' - render(nftables_conf, 'firewall/nftables.j2', firewall) return None @@ -474,8 +476,7 @@ def apply(firewall): apply_sysfs(firewall) - if firewall['group_resync']: - call_dependents() + call_dependents() # T970 Enable a resolver (systemd daemon) that checks # domain-group/fqdn addresses and update entries for domains by timeout diff --git a/src/conf_mode/load-balancing_wan.py b/src/conf_mode/load-balancing_wan.py index ad9c80d72..5da0b906b 100755 --- a/src/conf_mode/load-balancing_wan.py +++ b/src/conf_mode/load-balancing_wan.py @@ -21,6 +21,7 @@ from shutil import rmtree from vyos.base import Warning from vyos.config import Config +from vyos.configdep import set_dependents, call_dependents from vyos.utils.process import cmd from vyos.template import render from vyos import ConfigError @@ -49,6 +50,8 @@ def get_config(config=None): if lb.from_defaults(['rule', rule, 'limit']): del lb['rule'][rule]['limit'] + set_dependents('conntrack', conf) + return lb @@ -132,6 +135,8 @@ def apply(lb): cmd('sudo sysctl -w net.netfilter.nf_conntrack_acct=1') cmd(f'systemctl restart {systemd_service}') + call_dependents() + return None diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py index ffd4a33e7..bd9b5162c 100755 --- a/src/conf_mode/nat.py +++ b/src/conf_mode/nat.py @@ -18,13 +18,12 @@ import jmespath import json import os -from distutils.version import LooseVersion -from platform import release as kernel_version from sys import exit from netifaces import interfaces from vyos.base import Warning from vyos.config import Config +from vyos.configdep import set_dependents, call_dependents from vyos.template import render from vyos.template import is_ip_network from vyos.utils.kernel import check_kmod @@ -38,10 +37,7 @@ from vyos import ConfigError from vyos import airbag airbag.enable() -if LooseVersion(kernel_version()) > LooseVersion('5.1'): - k_mod = ['nft_nat', 'nft_chain_nat'] -else: - k_mod = ['nft_nat', 'nft_chain_nat_ipv4'] +k_mod = ['nft_nat', 'nft_chain_nat'] nftables_nat_config = '/run/nftables_nat.conf' nftables_static_nat_conf = '/run/nftables_static-nat-rules.nft' @@ -53,18 +49,27 @@ valid_groups = [ 'port_group' ] -def get_handler(json, chain, target): - """ Get nftable rule handler number of given chain/target combination. - Handler is required when adding NAT/Conntrack helper targets """ - for x in json: - if x['chain'] != chain: - continue - if x['target'] != target: - continue - return x['handle'] +def get_config(config=None): + if config: + conf = config + else: + conf = Config() - return None + base = ['nat'] + nat = conf.get_config_dict(base, key_mangling=('-', '_'), + get_first_key=True, + with_recursive_defaults=True) + set_dependents('conntrack', conf) + + if not conf.exists(base): + nat['deleted'] = '' + return nat + + nat['firewall_group'] = conf.get_config_dict(['firewall', 'group'], key_mangling=('-', '_'), get_first_key=True, + no_tag_node_value_mangle=True) + + return nat def verify_rule(config, err_msg, groups_dict): """ Common verify steps used for both source and destination NAT """ @@ -105,7 +110,7 @@ def verify_rule(config, err_msg, groups_dict): group_obj = dict_search_args(groups_dict, group, group_name) if group_obj is None: - raise ConfigError(f'Invalid {error_group} "{group_name}" on firewall rule') + raise ConfigError(f'Invalid {error_group} "{group_name}" on nat rule') if not group_obj: Warning(f'{error_group} "{group_name}" has no members!') @@ -129,62 +134,11 @@ def verify_rule(config, err_msg, groups_dict): if count != 100: Warning(f'Sum of weight for nat load balance rule is not 100. You may get unexpected behaviour') -def get_config(config=None): - if config: - conf = config - else: - conf = Config() - - base = ['nat'] - nat = conf.get_config_dict(base, key_mangling=('-', '_'), - get_first_key=True, - with_recursive_defaults=True) - - # read in current nftable (once) for further processing - tmp = cmd('nft -j list table raw') - nftable_json = json.loads(tmp) - - # condense the full JSON table into a list with only relevand informations - pattern = 'nftables[?rule].rule[?expr[].jump].{chain: chain, handle: handle, target: expr[].jump.target | [0]}' - condensed_json = jmespath.search(pattern, nftable_json) - - if not conf.exists(base): - if get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_HELPER'): - nat['helper_functions'] = 'remove' - - # Retrieve current table handler positions - nat['pre_ct_ignore'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_HELPER') - nat['pre_ct_conntrack'] = get_handler(condensed_json, 'PREROUTING', 'NAT_CONNTRACK') - nat['out_ct_ignore'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_HELPER') - nat['out_ct_conntrack'] = get_handler(condensed_json, 'OUTPUT', 'NAT_CONNTRACK') - nat['deleted'] = '' - return nat - - nat['firewall_group'] = conf.get_config_dict(['firewall', 'group'], key_mangling=('-', '_'), get_first_key=True, - no_tag_node_value_mangle=True) - - # check if NAT connection tracking helpers need to be set up - this has to - # be done only once - if not get_handler(condensed_json, 'PREROUTING', 'NAT_CONNTRACK'): - nat['helper_functions'] = 'add' - - # Retrieve current table handler positions - nat['pre_ct_ignore'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_IGNORE') - nat['pre_ct_conntrack'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_PREROUTING_HOOK') - nat['out_ct_ignore'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_IGNORE') - nat['out_ct_conntrack'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_OUTPUT_HOOK') - - return nat - def verify(nat): if not nat or 'deleted' in nat: # no need to verify the CLI as NAT is going to be deactivated return None - if 'helper_functions' in nat: - if not (nat['pre_ct_ignore'] or nat['pre_ct_conntrack'] or nat['out_ct_ignore'] or nat['out_ct_conntrack']): - raise Exception('could not determine nftable ruleset handlers') - if dict_search('source.rule', nat): for rule, config in dict_search('source.rule', nat).items(): err_msg = f'Source NAT configuration error in rule {rule}:' @@ -265,6 +219,8 @@ def apply(nat): os.unlink(nftables_nat_config) os.unlink(nftables_static_nat_conf) + call_dependents() + return None if __name__ == '__main__': diff --git a/src/conf_mode/nat66.py b/src/conf_mode/nat66.py index ed716b2a2..4c1ead258 100755 --- a/src/conf_mode/nat66.py +++ b/src/conf_mode/nat66.py @@ -23,6 +23,7 @@ from netifaces import interfaces from vyos.base import Warning from vyos.config import Config +from vyos.configdep import set_dependents, call_dependents from vyos.template import render from vyos.utils.process import cmd from vyos.utils.kernel import check_kmod @@ -36,18 +37,6 @@ k_mod = ['nft_nat', 'nft_chain_nat'] nftables_nat66_config = '/run/nftables_nat66.nft' -def get_handler(json, chain, target): - """ Get nftable rule handler number of given chain/target combination. - Handler is required when adding NAT66/Conntrack helper targets """ - for x in json: - if x['chain'] != chain: - continue - if x['target'] != target: - continue - return x['handle'] - - return None - def get_config(config=None): if config: conf = config @@ -57,35 +46,10 @@ def get_config(config=None): base = ['nat66'] nat = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) - # read in current nftable (once) for further processing - tmp = cmd('nft -j list table ip6 raw') - nftable_json = json.loads(tmp) - - # condense the full JSON table into a list with only relevand informations - pattern = 'nftables[?rule].rule[?expr[].jump].{chain: chain, handle: handle, target: expr[].jump.target | [0]}' - condensed_json = jmespath.search(pattern, nftable_json) + set_dependents('conntrack', conf) if not conf.exists(base): - nat['helper_functions'] = 'remove' - nat['pre_ct_ignore'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_HELPER') - nat['pre_ct_conntrack'] = get_handler(condensed_json, 'PREROUTING', 'NAT_CONNTRACK') - nat['out_ct_ignore'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_HELPER') - nat['out_ct_conntrack'] = get_handler(condensed_json, 'OUTPUT', 'NAT_CONNTRACK') nat['deleted'] = '' - return nat - - # check if NAT66 connection tracking helpers need to be set up - this has to - # be done only once - if not get_handler(condensed_json, 'PREROUTING', 'NAT_CONNTRACK'): - nat['helper_functions'] = 'add' - - # Retrieve current table handler positions - nat['pre_ct_ignore'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_IGNORE') - nat['pre_ct_conntrack'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_PREROUTING_HOOK') - nat['out_ct_ignore'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_IGNORE') - nat['out_ct_conntrack'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_OUTPUT_HOOK') - else: - nat['helper_functions'] = 'has' return nat @@ -94,10 +58,6 @@ def verify(nat): # no need to verify the CLI as NAT66 is going to be deactivated return None - if 'helper_functions' in nat and nat['helper_functions'] != 'has': - if not (nat['pre_ct_conntrack'] or nat['out_ct_conntrack']): - raise Exception('could not determine nftable ruleset handlers') - if dict_search('source.rule', nat): for rule, config in dict_search('source.rule', nat).items(): err_msg = f'Source NAT66 configuration error in rule {rule}:' @@ -147,6 +107,7 @@ def apply(nat): return None cmd(f'nft -f {nftables_nat66_config}') + call_dependents() return None diff --git a/src/conf_mode/system_flow-accounting.py b/src/conf_mode/system_flow-accounting.py index f29fc94fb..206f513c8 100755 --- a/src/conf_mode/system_flow-accounting.py +++ b/src/conf_mode/system_flow-accounting.py @@ -38,7 +38,7 @@ uacctd_conf_path = '/run/pmacct/uacctd.conf' systemd_service = 'uacctd.service' systemd_override = f'/run/systemd/system/{systemd_service}.d/override.conf' nftables_nflog_table = 'raw' -nftables_nflog_chain = 'VYOS_CT_PREROUTING_HOOK' +nftables_nflog_chain = 'VYOS_PREROUTING_HOOK' egress_nftables_nflog_table = 'inet mangle' egress_nftables_nflog_chain = 'FORWARD' diff --git a/src/op_mode/firewall.py b/src/op_mode/firewall.py index d426b62e5..36bb013fe 100755 --- a/src/op_mode/firewall.py +++ b/src/op_mode/firewall.py @@ -113,19 +113,14 @@ def output_firewall_name(family, hook, priority, firewall_conf, single_rule_id=N if hook in ['input', 'forward', 'output']: def_action = firewall_conf['default_action'] if 'default_action' in firewall_conf else 'accept' - row = ['default', def_action, 'all'] - rule_details = details['default-action'] - row.append(rule_details.get('packets', 0)) - row.append(rule_details.get('bytes', 0)) - rows.append(row) + else: + def_action = firewall_conf['default_action'] if 'default_action' in firewall_conf else 'drop' + row = ['default', def_action, 'all'] + rule_details = details['default-action'] + row.append(rule_details.get('packets', 0)) + row.append(rule_details.get('bytes', 0)) - elif 'default_action' in firewall_conf and not single_rule_id: - row = ['default', firewall_conf['default_action'], 'all'] - if 'default-action' in details: - rule_details = details['default-action'] - row.append(rule_details.get('packets', 0)) - row.append(rule_details.get('bytes', 0)) - rows.append(row) + rows.append(row) if rows: header = ['Rule', 'Action', 'Protocol', 'Packets', 'Bytes', 'Conditions'] @@ -314,7 +309,7 @@ def show_firewall_group(name=None): family = ['ipv6'] group_type = 'network_group' else: - family = ['ipv4', 'ipv6'] + family = ['ipv4', 'ipv6', 'bridge'] for item in family: # Look references in firewall @@ -540,4 +535,4 @@ if __name__ == '__main__': elif args.action == 'show_statistics': show_statistics() elif args.action == 'show_summary': - show_summary() \ No newline at end of file + show_summary() -- cgit v1.2.3