diff --git a/interface-definitions/firewall.xml.in b/interface-definitions/firewall.xml.in
index 63095bc20..3250794d3 100644
--- a/interface-definitions/firewall.xml.in
+++ b/interface-definitions/firewall.xml.in
@@ -1,692 +1,692 @@
 <?xml version="1.0"?>
 <interfaceDefinition>
   <node name="firewall" owner="${vyos_conf_scripts_dir}/firewall.py">
     <properties>
       <priority>199</priority>
       <help>Firewall</help>
     </properties>
     <children>
       <leafNode name="all-ping">
         <properties>
           <help>Policy for handling of all IPv4 ICMP echo requests</help>
           <completionHelp>
             <list>enable disable</list>
           </completionHelp>
           <valueHelp>
             <format>enable</format>
             <description>Enable processing of all IPv4 ICMP echo requests</description>
           </valueHelp>
           <valueHelp>
             <format>disable</format>
             <description>Disable processing of all IPv4 ICMP echo requests</description>
           </valueHelp>
           <constraint>
             <regex>(enable|disable)</regex>
           </constraint>
         </properties>
         <defaultValue>enable</defaultValue>
       </leafNode>
       <leafNode name="broadcast-ping">
         <properties>
           <help>Policy for handling broadcast IPv4 ICMP echo and timestamp requests</help>
           <completionHelp>
             <list>enable disable</list>
           </completionHelp>
           <valueHelp>
             <format>enable</format>
             <description>Enable processing of broadcast IPv4 ICMP echo/timestamp requests</description>
           </valueHelp>
           <valueHelp>
             <format>disable</format>
             <description>Disable processing of broadcast IPv4 ICMP echo/timestamp requests</description>
           </valueHelp>
           <constraint>
             <regex>(enable|disable)</regex>
           </constraint>
         </properties>
         <defaultValue>disable</defaultValue>
       </leafNode>
       <leafNode name="config-trap">
         <properties>
           <help>SNMP trap generation on firewall configuration changes</help>
           <completionHelp>
             <list>enable disable</list>
           </completionHelp>
           <valueHelp>
             <format>enable</format>
             <description>Enable sending SNMP trap on firewall configuration change</description>
           </valueHelp>
           <valueHelp>
             <format>disable</format>
             <description>Disable sending SNMP trap on firewall configuration change</description>
           </valueHelp>
           <constraint>
             <regex>(enable|disable)</regex>
           </constraint>
         </properties>
         <defaultValue>disable</defaultValue>
       </leafNode>
       <node name="group">
         <properties>
           <help>Firewall group</help>
         </properties>
         <children>
           <tagNode name="address-group">
             <properties>
               <help>Firewall address-group</help>
               <constraint>
                 <regex>[a-zA-Z0-9][\w\-\.]*</regex>
               </constraint>
             </properties>
             <children>
               <leafNode name="address">
                 <properties>
                   <help>Address-group member</help>
                   <valueHelp>
                     <format>ipv4</format>
                     <description>IPv4 address to match</description>
                   </valueHelp>
                   <valueHelp>
                     <format>ipv4range</format>
                     <description>IPv4 range to match (e.g. 10.0.0.1-10.0.0.200)</description>
                   </valueHelp>
                   <constraint>
                     <validator name="ipv4-address"/>
                     <validator name="ipv4-range"/>
                   </constraint>
                   <multi/>
                 </properties>
               </leafNode>
               #include <include/generic-description.xml.i>
             </children>
           </tagNode>
           <tagNode name="domain-group">
             <properties>
               <help>Firewall domain-group</help>
               <constraint>
                 <regex>[a-zA-Z_][a-zA-Z0-9][\w\-\.]*</regex>
               </constraint>
               <constraintErrorMessage>Name of domain-group can only contain alpha-numeric letters, hyphen, underscores and not start with numeric</constraintErrorMessage>
             </properties>
             <children>
               <leafNode name="address">
                 <properties>
                   <help>Domain-group member</help>
                   <valueHelp>
                     <format>txt</format>
                     <description>Domain address to match</description>
                   </valueHelp>
                   <constraint>
-                    <regex>[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}?(\/.*)?</regex>
+                    <regex>[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,99}?(\/.*)?</regex>
                   </constraint>
                   <multi/>
                 </properties>
               </leafNode>
               #include <include/generic-description.xml.i>
             </children>
           </tagNode>
           <tagNode name="ipv6-address-group">
             <properties>
               <help>Firewall ipv6-address-group</help>
               <constraint>
                 <regex>[a-zA-Z0-9][\w\-\.]*</regex>
               </constraint>
             </properties>
             <children>
               <leafNode name="address">
                 <properties>
                   <help>Address-group member</help>
                   <valueHelp>
                     <format>ipv6</format>
                     <description>IPv6 address to match</description>
                   </valueHelp>
                   <valueHelp>
                     <format>ipv6range</format>
                     <description>IPv6 range to match (e.g. 2002::1-2002::ff)</description>
                   </valueHelp>
                   <constraint>
                     <validator name="ipv6-address"/>
                     <validator name="ipv6-range"/>
                   </constraint>
                   <multi/>
                 </properties>
               </leafNode>
               #include <include/generic-description.xml.i>
             </children>
           </tagNode>
           <tagNode name="ipv6-network-group">
             <properties>
               <help>Firewall ipv6-network-group</help>
               <constraint>
                 <regex>[a-zA-Z0-9][\w\-\.]*</regex>
               </constraint>
             </properties>
             <children>
               #include <include/generic-description.xml.i>
               <leafNode name="network">
                 <properties>
                   <help>Network-group member</help>
                   <valueHelp>
                     <format>ipv6net</format>
                     <description>IPv6 address to match</description>
                   </valueHelp>
                   <constraint>
                     <validator name="ipv6-prefix"/>
                   </constraint>
                   <multi/>
                 </properties>
               </leafNode>
             </children>
           </tagNode>
           <tagNode name="mac-group">
             <properties>
               <help>Firewall mac-group</help>
               <constraint>
                 <regex>[a-zA-Z0-9][\w\-\.]*</regex>
               </constraint>
             </properties>
             <children>
               #include <include/generic-description.xml.i>
               <leafNode name="mac-address">
                 <properties>
                   <help>Mac-group member</help>
                   <valueHelp>
                     <format>&lt;MAC address&gt;</format>
                     <description>MAC address to match</description>
                   </valueHelp>
                   <constraint>
                     <validator name="mac-address"/>
                   </constraint>
                   <multi/>
                 </properties>
               </leafNode>
             </children>
           </tagNode>
           <tagNode name="network-group">
             <properties>
               <help>Firewall network-group</help>
               <constraint>
                 <regex>[a-zA-Z0-9][\w\-\.]*</regex>
               </constraint>
             </properties>
             <children>
               #include <include/generic-description.xml.i>
               <leafNode name="network">
                 <properties>
                   <help>Network-group member</help>
                   <valueHelp>
                     <format>ipv4net</format>
                     <description>IPv4 Subnet to match</description>
                   </valueHelp>
                   <constraint>
                     <validator name="ipv4-prefix"/>
                   </constraint>
                   <multi/>
                 </properties>
               </leafNode>
             </children>
           </tagNode>
           <tagNode name="port-group">
             <properties>
               <help>Firewall port-group</help>
               <constraint>
                 <regex>[a-zA-Z0-9][\w\-\.]*</regex>
               </constraint>
             </properties>
             <children>
               #include <include/generic-description.xml.i>
               <leafNode name="port">
                 <properties>
                   <help>Port-group member</help>
                   <valueHelp>
                     <format>txt</format>
                     <description>Named port (any name in /etc/services, e.g., http)</description>
                   </valueHelp>
                   <valueHelp>
                     <format>u32:1-65535</format>
                     <description>Numbered port</description>
                   </valueHelp>
                   <valueHelp>
                     <format>start-end</format>
                     <description>Numbered port range (e.g. 1001-1050)</description>
                   </valueHelp>
                   <multi/>
                   <constraint>
                     <validator name="port-range"/>
                   </constraint>
                 </properties>
               </leafNode>
             </children>
           </tagNode>
         </children>
       </node>
       <leafNode name="ip-src-route">
         <properties>
           <help>Policy for handling IPv4 packets with source route option</help>
           <completionHelp>
             <list>enable disable</list>
           </completionHelp>
           <valueHelp>
             <format>enable</format>
             <description>Enable processing of IPv4 packets with source route option</description>
           </valueHelp>
           <valueHelp>
             <format>disable</format>
             <description>Disable processing of IPv4 packets with source route option</description>
           </valueHelp>
           <constraint>
             <regex>(enable|disable)</regex>
           </constraint>
         </properties>
         <defaultValue>disable</defaultValue>
       </leafNode>
       <tagNode name="ipv6-name">
         <properties>
           <help>IPv6 firewall rule-set name</help>
           <constraint>
             <regex>[a-zA-Z0-9][\w\-\.]*</regex>
           </constraint>
         </properties>
         <children>
           #include <include/firewall/name-default-action.xml.i>
           #include <include/firewall/name-default-log.xml.i>
           #include <include/generic-description.xml.i>
           <tagNode name="rule">
             <properties>
               <help>Firewall rule number (IPv6)</help>
               <valueHelp>
                 <format>u32:1-999999</format>
                 <description>Number for this Firewall rule</description>
               </valueHelp>
               <constraint>
                 <validator name="numeric" argument="--range 1-999999"/>
               </constraint>
               <constraintErrorMessage>Firewall rule number must be between 1 and 999999</constraintErrorMessage>
             </properties>
             <children>
               #include <include/firewall/action.xml.i>
               #include <include/generic-description.xml.i>
               <node name="destination">
                 <properties>
                   <help>Destination parameters</help>
                 </properties>
                 <children>
                   #include <include/firewall/address-ipv6.xml.i>
                   #include <include/firewall/source-destination-group-ipv6.xml.i>
                   #include <include/firewall/port.xml.i>
                 </children>
               </node>
               <node name="source">
                 <properties>
                   <help>Source parameters</help>
                 </properties>
                 <children>
                   #include <include/firewall/address-ipv6.xml.i>
                   #include <include/firewall/source-destination-group-ipv6.xml.i>
                   #include <include/firewall/port.xml.i>
                 </children>
               </node>
               #include <include/firewall/common-rule.xml.i>
               <node name="hop-limit">
                 <properties>
                   <help>Hop Limit</help>
                 </properties>
                 <children>
                   <leafNode name="eq">
                     <properties>
                       <help>Value to match a hop limit equal to it</help>
                       <valueHelp>
                         <format>u32:0-255</format>
                         <description>Hop limit equal to value</description>
                       </valueHelp>
                       <constraint>
                         <validator name="numeric" argument="--range 0-255"/>
                       </constraint>
                     </properties>
                   </leafNode>
                   <leafNode name="gt">
                     <properties>
                       <help>Value to match a hop limit greater than or equal to it</help>
                       <valueHelp>
                         <format>u32:0-255</format>
                         <description>Hop limit greater than value</description>
                       </valueHelp>
                       <constraint>
                         <validator name="numeric" argument="--range 0-255"/>
                       </constraint>
                     </properties>
                   </leafNode>
                   <leafNode name="lt">
                     <properties>
                       <help>Value to match a hop limit less than or equal to it</help>
                       <valueHelp>
                         <format>u32:0-255</format>
                         <description>Hop limit less than value</description>
                       </valueHelp>
                       <constraint>
                         <validator name="numeric" argument="--range 0-255"/>
                       </constraint>
                     </properties>
                   </leafNode>
                 </children>
               </node>
               <node name="icmpv6">
                 <properties>
                   <help>ICMPv6 type and code information</help>
                 </properties>
                 <children>
                   <leafNode name="code">
                     <properties>
                       <help>ICMPv6 code (0-255)</help>
                       <valueHelp>
                         <format>u32:0-255</format>
                         <description>ICMPv6 code (0-255)</description>
                       </valueHelp>
                       <constraint>
                         <validator name="numeric" argument="--range 0-255"/>
                       </constraint>
                     </properties>
                   </leafNode>
                   <leafNode name="type">
                     <properties>
                       <help>ICMPv6 type (0-255)</help>
                       <valueHelp>
                         <format>u32:0-255</format>
                         <description>ICMPv6 type (0-255)</description>
                       </valueHelp>
                       <constraint>
                         <validator name="numeric" argument="--range 0-255"/>
                       </constraint>
                     </properties>
                   </leafNode>
                   #include <include/firewall/icmpv6-type-name.xml.i>
                 </children>
               </node>
             </children>
           </tagNode>
         </children>
       </tagNode>
       <leafNode name="ipv6-receive-redirects">
         <properties>
           <help>Policy for handling received ICMPv6 redirect messages</help>
           <completionHelp>
             <list>enable disable</list>
           </completionHelp>
           <valueHelp>
             <format>enable</format>
             <description>Enable processing of received ICMPv6 redirect messages</description>
           </valueHelp>
           <valueHelp>
             <format>disable</format>
             <description>Disable processing of received ICMPv6 redirect messages</description>
           </valueHelp>
           <constraint>
             <regex>(enable|disable)</regex>
           </constraint>
         </properties>
         <defaultValue>disable</defaultValue>
       </leafNode>
       <leafNode name="ipv6-src-route">
         <properties>
           <help>Policy for handling IPv6 packets with routing extension header</help>
           <completionHelp>
             <list>enable disable</list>
           </completionHelp>
           <valueHelp>
             <format>enable</format>
             <description>Enable processing of IPv6 packets with routing header type 2</description>
           </valueHelp>
           <valueHelp>
             <format>disable</format>
             <description>Disable processing of IPv6 packets with routing header</description>
           </valueHelp>
           <constraint>
             <regex>(enable|disable)</regex>
           </constraint>
         </properties>
         <defaultValue>disable</defaultValue>
       </leafNode>
       <leafNode name="log-martians">
         <properties>
           <help>Policy for logging IPv4 packets with invalid addresses</help>
           <completionHelp>
             <list>enable disable</list>
           </completionHelp>
           <valueHelp>
             <format>enable</format>
             <description>Enable logging of IPv4 packets with invalid addresses</description>
           </valueHelp>
           <valueHelp>
             <format>disable</format>
             <description>Disable logging of Ipv4 packets with invalid addresses</description>
           </valueHelp>
           <constraint>
             <regex>(enable|disable)</regex>
           </constraint>
         </properties>
         <defaultValue>enable</defaultValue>
       </leafNode>
       <tagNode name="name">
         <properties>
           <help>IPv4 firewall rule-set name</help>
           <constraint>
             <regex>[a-zA-Z0-9][\w\-\.]*</regex>
           </constraint>
         </properties>
         <children>
           #include <include/firewall/name-default-action.xml.i>
           #include <include/firewall/name-default-log.xml.i>
           #include <include/generic-description.xml.i>
           <tagNode name="rule">
             <properties>
               <help>Firewall rule number (IPv4)</help>
               <valueHelp>
                 <format>u32:1-999999</format>
                 <description>Number for this Firewall rule</description>
               </valueHelp>
               <constraint>
                 <validator name="numeric" argument="--range 1-999999"/>
               </constraint>
               <constraintErrorMessage>Firewall rule number must be between 1 and 999999</constraintErrorMessage>
             </properties>
             <children>
               #include <include/firewall/action.xml.i>
               #include <include/generic-description.xml.i>
               <node name="destination">
                 <properties>
                   <help>Destination parameters</help>
                 </properties>
                 <children>
                   #include <include/firewall/address.xml.i>
                   #include <include/firewall/source-destination-group.xml.i>
                   #include <include/firewall/port.xml.i>
                 </children>
               </node>
               <node name="source">
                 <properties>
                   <help>Source parameters</help>
                 </properties>
                 <children>
                   #include <include/firewall/address.xml.i>
                   #include <include/firewall/source-destination-group.xml.i>
                   #include <include/firewall/port.xml.i>
                 </children>
               </node>
               #include <include/firewall/common-rule.xml.i>
               <node name="icmp">
                 <properties>
                   <help>ICMP type and code information</help>
                 </properties>
                 <children>
                   <leafNode name="code">
                     <properties>
                       <help>ICMP code (0-255)</help>
                       <valueHelp>
                         <format>u32:0-255</format>
                         <description>ICMP code (0-255)</description>
                       </valueHelp>
                       <constraint>
                         <validator name="numeric" argument="--range 0-255"/>
                       </constraint>
                     </properties>
                   </leafNode>
                   <leafNode name="type">
                     <properties>
                       <help>ICMP type (0-255)</help>
                       <valueHelp>
                         <format>u32:0-255</format>
                         <description>ICMP type (0-255)</description>
                       </valueHelp>
                       <constraint>
                         <validator name="numeric" argument="--range 0-255"/>
                       </constraint>
                     </properties>
                   </leafNode>
                   #include <include/firewall/icmp-type-name.xml.i>
                 </children>
               </node>
             </children>
           </tagNode>
         </children>
       </tagNode>
       <leafNode name="receive-redirects">
         <properties>
           <help>Policy for handling received IPv4 ICMP redirect messages</help>
           <completionHelp>
             <list>enable disable</list>
           </completionHelp>
           <valueHelp>
             <format>enable</format>
             <description>Enable processing of received IPv4 ICMP redirect messages</description>
           </valueHelp>
           <valueHelp>
             <format>disable</format>
             <description>Disable processing of received IPv4 ICMP redirect messages</description>
           </valueHelp>
           <constraint>
             <regex>(enable|disable)</regex>
           </constraint>
         </properties>
         <defaultValue>disable</defaultValue>
       </leafNode>
       <leafNode name="send-redirects">
         <properties>
           <help>Policy for sending IPv4 ICMP redirect messages</help>
           <completionHelp>
             <list>enable disable</list>
           </completionHelp>
           <valueHelp>
             <format>enable</format>
             <description>Enable sending IPv4 ICMP redirect messages</description>
           </valueHelp>
           <valueHelp>
             <format>disable</format>
             <description>Disable sending IPv4 ICMP redirect messages</description>
           </valueHelp>
           <constraint>
             <regex>(enable|disable)</regex>
           </constraint>
         </properties>
         <defaultValue>enable</defaultValue>
       </leafNode>
       <leafNode name="source-validation">
         <properties>
           <help>Policy for source validation by reversed path, as specified in RFC3704</help>
           <completionHelp>
             <list>strict loose disable</list>
           </completionHelp>
           <valueHelp>
             <format>strict</format>
             <description>Enable Strict Reverse Path Forwarding as defined in RFC3704</description>
           </valueHelp>
           <valueHelp>
             <format>loose</format>
             <description>Enable Loose Reverse Path Forwarding as defined in RFC3704</description>
           </valueHelp>
           <valueHelp>
             <format>disable</format>
             <description>No source validation</description>
           </valueHelp>
           <constraint>
             <regex>(strict|loose|disable)</regex>
           </constraint>
         </properties>
         <defaultValue>disable</defaultValue>
       </leafNode>
       <node name="state-policy">
         <properties>
           <help>Global firewall state-policy</help>
         </properties>
         <children>
           <node name="established">
             <properties>
               <help>Global firewall policy for packets part of an established connection</help>
             </properties>
             <children>
               #include <include/firewall/action-accept-drop-reject.xml.i>
               #include <include/firewall/rule-log-level.xml.i>
             </children>
           </node>
           <node name="invalid">
             <properties>
               <help>Global firewall policy for packets part of an invalid connection</help>
             </properties>
             <children>
               #include <include/firewall/action-accept-drop-reject.xml.i>
               #include <include/firewall/rule-log-level.xml.i>
             </children>
           </node>
           <node name="related">
             <properties>
               <help>Global firewall policy for packets part of a related connection</help>
             </properties>
             <children>
               #include <include/firewall/action-accept-drop-reject.xml.i>
               #include <include/firewall/rule-log-level.xml.i>
             </children>
           </node>
         </children>
       </node>
       <leafNode name="syn-cookies">
         <properties>
           <help>Policy for using TCP SYN cookies with IPv4</help>
           <completionHelp>
             <list>enable disable</list>
           </completionHelp>
           <valueHelp>
             <format>enable</format>
             <description>Enable use of TCP SYN cookies with IPv4</description>
           </valueHelp>
           <valueHelp>
             <format>disable</format>
             <description>Disable use of TCP SYN cookies with IPv4</description>
           </valueHelp>
           <constraint>
             <regex>(enable|disable)</regex>
           </constraint>
         </properties>
         <defaultValue>enable</defaultValue>
       </leafNode>
       <leafNode name="twa-hazards-protection">
         <properties>
           <help>RFC1337 TCP TIME-WAIT assasination hazards protection</help>
           <completionHelp>
             <list>enable disable</list>
           </completionHelp>
           <valueHelp>
             <format>enable</format>
             <description>Enable RFC1337 TIME-WAIT hazards protection</description>
           </valueHelp>
           <valueHelp>
             <format>disable</format>
             <description>Disable RFC1337 TIME-WAIT hazards protection</description>
           </valueHelp>
           <constraint>
             <regex>(enable|disable)</regex>
           </constraint>
         </properties>
         <defaultValue>disable</defaultValue>
       </leafNode>
     </children>
   </node>
 </interfaceDefinition>
diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py
index 335098bf1..fbe0a3a13 100755
--- a/src/conf_mode/firewall.py
+++ b/src/conf_mode/firewall.py
@@ -1,461 +1,462 @@
 #!/usr/bin/env python3
 #
 # Copyright (C) 2021-2022 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
 # published by the Free Software Foundation.
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import os
 import re
 
 from glob import glob
 from json import loads
 from sys import exit
 
 from vyos.base import Warning
 from vyos.config import Config
 from vyos.configdict import dict_merge
 from vyos.configdict import node_changed
 from vyos.configdiff import get_config_diff, Diff
 from vyos.firewall import get_ips_domains_dict
 from vyos.firewall import nft_add_set_elements
 from vyos.firewall import nft_flush_set
 from vyos.firewall import nft_init_set
 from vyos.firewall import nft_update_set_elements
 from vyos.template import render
 from vyos.util import call
 from vyos.util import cmd
 from vyos.util import dict_search_args
 from vyos.util import process_named_running
 from vyos.util import run
 from vyos.xml import defaults
 from vyos import ConfigError
 from vyos import airbag
 airbag.enable()
 
 policy_route_conf_script = '/usr/libexec/vyos/conf_mode/policy-route.py'
 
 nftables_conf = '/run/nftables.conf'
 nftables_defines_conf = '/run/nftables_defines.conf'
 
 sysfs_config = {
     'all_ping': {'sysfs': '/proc/sys/net/ipv4/icmp_echo_ignore_all', 'enable': '0', 'disable': '1'},
     'broadcast_ping': {'sysfs': '/proc/sys/net/ipv4/icmp_echo_ignore_broadcasts', 'enable': '0', 'disable': '1'},
     'ip_src_route': {'sysfs': '/proc/sys/net/ipv4/conf/*/accept_source_route'},
     'ipv6_receive_redirects': {'sysfs': '/proc/sys/net/ipv6/conf/*/accept_redirects'},
     'ipv6_src_route': {'sysfs': '/proc/sys/net/ipv6/conf/*/accept_source_route', 'enable': '0', 'disable': '-1'},
     'log_martians': {'sysfs': '/proc/sys/net/ipv4/conf/all/log_martians'},
     'receive_redirects': {'sysfs': '/proc/sys/net/ipv4/conf/*/accept_redirects'},
     'send_redirects': {'sysfs': '/proc/sys/net/ipv4/conf/*/send_redirects'},
     'source_validation': {'sysfs': '/proc/sys/net/ipv4/conf/*/rp_filter', 'disable': '0', 'strict': '1', 'loose': '2'},
     'syn_cookies': {'sysfs': '/proc/sys/net/ipv4/tcp_syncookies'},
     'twa_hazards_protection': {'sysfs': '/proc/sys/net/ipv4/tcp_rfc1337'}
 }
 
 NAME_PREFIX = 'NAME_'
 NAME6_PREFIX = 'NAME6_'
 
 preserve_chains = [
     'INPUT',
     'FORWARD',
     'OUTPUT',
     'VYOS_FW_FORWARD',
     'VYOS_FW_LOCAL',
     'VYOS_FW_OUTPUT',
     'VYOS_POST_FW',
     'VYOS_FRAG_MARK',
     'VYOS_FW6_FORWARD',
     'VYOS_FW6_LOCAL',
     'VYOS_FW6_OUTPUT',
     'VYOS_POST_FW6',
     'VYOS_FRAG6_MARK'
 ]
 
 nft_iface_chains = ['VYOS_FW_FORWARD', 'VYOS_FW_OUTPUT', 'VYOS_FW_LOCAL']
 nft6_iface_chains = ['VYOS_FW6_FORWARD', 'VYOS_FW6_OUTPUT', 'VYOS_FW6_LOCAL']
 
 valid_groups = [
     'address_group',
     'network_group',
     'port_group'
 ]
 
 snmp_change_type = {
     'unknown': 0,
     'add': 1,
     'delete': 2,
     'change': 3
 }
 snmp_event_source = 1
 snmp_trap_mib = 'VYATTA-TRAP-MIB'
 snmp_trap_name = 'mgmtEventTrap'
 
 def get_firewall_interfaces(conf):
     out = {}
     interfaces = conf.get_config_dict(['interfaces'], key_mangling=('-', '_'), get_first_key=True,
                                     no_tag_node_value_mangle=True)
     def find_interfaces(iftype_conf, output={}, prefix=''):
         for ifname, if_conf in iftype_conf.items():
             if 'firewall' in if_conf:
                 output[prefix + ifname] = if_conf['firewall']
             for vif in ['vif', 'vif_s', 'vif_c']:
                 if vif in if_conf:
                     output.update(find_interfaces(if_conf[vif], output, f'{prefix}{ifname}.'))
         return output
     for iftype, iftype_conf in interfaces.items():
         out.update(find_interfaces(iftype_conf))
     return out
 
 def get_firewall_zones(conf):
     used_v4 = []
     used_v6 = []
     zone_policy = conf.get_config_dict(['zone-policy'], key_mangling=('-', '_'), get_first_key=True,
                                     no_tag_node_value_mangle=True)
 
     if 'zone' in zone_policy:
         for zone, zone_conf in zone_policy['zone'].items():
             if 'from' in zone_conf:
                 for from_zone, from_conf in zone_conf['from'].items():
                     name = dict_search_args(from_conf, 'firewall', 'name')
                     if name:
                         used_v4.append(name)
 
                     ipv6_name = dict_search_args(from_conf, 'firewall', 'ipv6_name')
                     if ipv6_name:
                         used_v6.append(ipv6_name)
 
             if 'intra_zone_filtering' in zone_conf:
                 name = dict_search_args(zone_conf, 'intra_zone_filtering', 'firewall', 'name')
                 if name:
                     used_v4.append(name)
 
                 ipv6_name = dict_search_args(zone_conf, 'intra_zone_filtering', 'firewall', 'ipv6_name')
                 if ipv6_name:
                     used_v6.append(ipv6_name)
 
     return {'name': used_v4, 'ipv6_name': used_v6}
 
 def get_config(config=None):
     if config:
         conf = config
     else:
         conf = Config()
     base = ['firewall']
 
     firewall = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True,
                                     no_tag_node_value_mangle=True)
 
     default_values = defaults(base)
     firewall = dict_merge(default_values, firewall)
 
     firewall['policy_resync'] = bool('group' in firewall or node_changed(conf, base + ['group']))
     firewall['interfaces'] = get_firewall_interfaces(conf)
     firewall['zone_policy'] = get_firewall_zones(conf)
 
     if 'config_trap' in firewall and firewall['config_trap'] == 'enable':
         diff = get_config_diff(conf)
         firewall['trap_diff'] = diff.get_child_nodes_diff_str(base)
         firewall['trap_targets'] = conf.get_config_dict(['service', 'snmp', 'trap-target'],
                                         key_mangling=('-', '_'), get_first_key=True,
                                         no_tag_node_value_mangle=True)
 
     return firewall
 
 def verify_rule(firewall, rule_conf, ipv6):
     if 'action' not in rule_conf:
         raise ConfigError('Rule action must be defined')
 
     if 'fragment' in rule_conf:
         if {'match_frag', 'match_non_frag'} <= set(rule_conf['fragment']):
             raise ConfigError('Cannot specify both "match-frag" and "match-non-frag"')
 
     if 'limit' in rule_conf:
         if 'rate' in rule_conf['limit']:
             rate_int = re.sub(r'\D', '', rule_conf['limit']['rate'])
             if int(rate_int) < 1:
                 raise ConfigError('Limit rate integer cannot be less than 1')
 
     if 'ipsec' in rule_conf:
         if {'match_ipsec', 'match_non_ipsec'} <= set(rule_conf['ipsec']):
             raise ConfigError('Cannot specify both "match-ipsec" and "match-non-ipsec"')
 
     if 'recent' in rule_conf:
         if not {'count', 'time'} <= set(rule_conf['recent']):
             raise ConfigError('Recent "count" and "time" values must be defined')
 
     tcp_flags = dict_search_args(rule_conf, 'tcp', 'flags')
     if tcp_flags:
         if dict_search_args(rule_conf, 'protocol') != 'tcp':
             raise ConfigError('Protocol must be tcp when specifying tcp flags')
 
         not_flags = dict_search_args(rule_conf, 'tcp', 'flags', 'not')
         if not_flags:
             duplicates = [flag for flag in tcp_flags if flag in not_flags]
             if duplicates:
                 raise ConfigError(f'Cannot match a tcp flag as set and not set')
 
     if 'protocol' in rule_conf:
         if rule_conf['protocol'] == 'icmp' and ipv6:
             raise ConfigError(f'Cannot match IPv4 ICMP protocol on IPv6, use ipv6-icmp')
         if rule_conf['protocol'] == 'ipv6-icmp' and not ipv6:
             raise ConfigError(f'Cannot match IPv6 ICMP protocol on IPv4, use icmp')
 
     for side in ['destination', 'source']:
         if side in rule_conf:
             side_conf = rule_conf[side]
 
             if 'group' in side_conf:
                 if {'address_group', 'network_group'} <= set(side_conf['group']):
                     raise ConfigError('Only one address-group or network-group can be specified')
 
                 for group in valid_groups:
                     if group in side_conf['group']:
                         group_name = side_conf['group'][group]
 
                         if group_name and group_name[0] == '!':
                             group_name = group_name[1:]
 
                         fw_group = f'ipv6_{group}' if ipv6 and group in ['address_group', 'network_group'] else group
                         error_group = fw_group.replace("_", "-")
                         group_obj = dict_search_args(firewall, 'group', fw_group, group_name)
 
                         if group_obj is None:
                             raise ConfigError(f'Invalid {error_group} "{group_name}" on firewall rule')
 
                         if not group_obj:
                             Warning(f'{error_group} "{group_name}" has no members!')
 
             if 'port' in side_conf or dict_search_args(side_conf, 'group', 'port_group'):
                 if 'protocol' not in rule_conf:
                     raise ConfigError('Protocol must be defined if specifying a port or port-group')
 
                 if rule_conf['protocol'] not in ['tcp', 'udp', 'tcp_udp']:
                     raise ConfigError('Protocol must be tcp, udp, or tcp_udp when specifying a port or port-group')
 
 def verify(firewall):
     if 'config_trap' in firewall and firewall['config_trap'] == 'enable':
         if not firewall['trap_targets']:
             raise ConfigError(f'Firewall config-trap enabled but "service snmp trap-target" is not defined')
 
     for name in ['name', 'ipv6_name']:
         if name in firewall:
             for name_id, name_conf in firewall[name].items():
                 if name_id in preserve_chains:
                     raise ConfigError(f'Firewall name "{name_id}" is reserved for VyOS')
 
                 if name_id.startswith("VZONE"):
                     raise ConfigError(f'Firewall name "{name_id}" uses reserved prefix')
 
                 if 'rule' in name_conf:
                     for rule_id, rule_conf in name_conf['rule'].items():
                         verify_rule(firewall, rule_conf, name == 'ipv6_name')
 
     for ifname, if_firewall in firewall['interfaces'].items():
         for direction in ['in', 'out', 'local']:
             name = dict_search_args(if_firewall, direction, 'name')
             ipv6_name = dict_search_args(if_firewall, direction, 'ipv6_name')
 
             if name and dict_search_args(firewall, 'name', name) == None:
                 raise ConfigError(f'Firewall name "{name}" is still referenced on interface {ifname}')
 
             if ipv6_name and dict_search_args(firewall, 'ipv6_name', ipv6_name) == None:
                 raise ConfigError(f'Firewall ipv6-name "{ipv6_name}" is still referenced on interface {ifname}')
 
     for fw_name, used_names in firewall['zone_policy'].items():
         for name in used_names:
             if dict_search_args(firewall, fw_name, name) == None:
                 raise ConfigError(f'Firewall {fw_name.replace("_", "-")} "{name}" is still referenced in zone-policy')
 
     return None
 
 def cleanup_rule(table, jump_chain):
     commands = []
     chains = nft_iface_chains if table == 'ip filter' else nft6_iface_chains
     for chain in chains:
         results = cmd(f'nft -a list chain {table} {chain}').split("\n")
         for line in results:
             if f'jump {jump_chain}' in line:
                 handle_search = re.search('handle (\d+)', line)
                 if handle_search:
                     commands.append(f'delete rule {table} {chain} handle {handle_search[1]}')
     return commands
 
 def cleanup_commands(firewall):
     commands = []
     commands_end = []
     for table in ['ip filter', 'ip6 filter']:
         state_chain = 'VYOS_STATE_POLICY' if table == 'ip filter' else 'VYOS_STATE_POLICY6'
         json_str = cmd(f'nft -j list table {table}')
         obj = loads(json_str)
         if 'nftables' not in obj:
             continue
         for item in obj['nftables']:
             if 'chain' in item:
                 chain = item['chain']['name']
                 if chain in ['VYOS_STATE_POLICY', 'VYOS_STATE_POLICY6']:
                     if 'state_policy' not in firewall:
                         commands.append(f'delete chain {table} {chain}')
                     else:
                         commands.append(f'flush chain {table} {chain}')
                 elif chain not in preserve_chains and not chain.startswith("VZONE"):
                     if table == 'ip filter' and dict_search_args(firewall, 'name', chain.replace(NAME_PREFIX, "", 1)) != None:
                         commands.append(f'flush chain {table} {chain}')
                     elif table == 'ip6 filter' and dict_search_args(firewall, 'ipv6_name', chain.replace(NAME6_PREFIX, "", 1)) != None:
                         commands.append(f'flush chain {table} {chain}')
                     else:
                         commands += cleanup_rule(table, chain)
                         commands.append(f'delete chain {table} {chain}')
             elif 'rule' in item:
                 rule = item['rule']
                 if rule['chain'] in ['VYOS_FW_FORWARD', 'VYOS_FW_OUTPUT', 'VYOS_FW_LOCAL', 'VYOS_FW6_FORWARD', 'VYOS_FW6_OUTPUT', 'VYOS_FW6_LOCAL']:
                     if 'expr' in rule and any([True for expr in rule['expr'] if dict_search_args(expr, 'jump', 'target') == state_chain]):
                         if 'state_policy' not in firewall:
                             chain = rule['chain']
                             handle = rule['handle']
                             commands.append(f'delete rule {table} {chain} handle {handle}')
             elif 'set' in item:
                 set_name = item['set']['name']
                 commands_end.append(f'delete set {table} {set_name}')
     return commands + commands_end
 
 def generate(firewall):
     if not os.path.exists(nftables_conf):
         firewall['first_install'] = True
     else:
         firewall['cleanup_commands'] = cleanup_commands(firewall)
 
     render(nftables_conf, 'firewall/nftables.j2', firewall)
     render(nftables_defines_conf, 'firewall/nftables-defines.j2', firewall)
     return None
 
 def apply_sysfs(firewall):
     for name, conf in sysfs_config.items():
         paths = glob(conf['sysfs'])
         value = None
 
         if name in firewall:
             conf_value = firewall[name]
 
             if conf_value in conf:
                 value = conf[conf_value]
             elif conf_value == 'enable':
                 value = '1'
             elif conf_value == 'disable':
                 value = '0'
 
         if value:
             for path in paths:
                 with open(path, 'w') as f:
                     f.write(value)
 
 def post_apply_trap(firewall):
     if 'first_install' in firewall:
         return None
 
     if 'config_trap' not in firewall or firewall['config_trap'] != 'enable':
         return None
 
     if not process_named_running('snmpd'):
         return None
 
     trap_username = os.getlogin()
 
     for host, target_conf in firewall['trap_targets'].items():
         community = target_conf['community'] if 'community' in target_conf else 'public'
         port = int(target_conf['port']) if 'port' in target_conf else 162
 
         base_cmd = f'snmptrap -v2c -c {community} {host}:{port} 0 {snmp_trap_mib}::{snmp_trap_name} '
 
         for change_type, changes in firewall['trap_diff'].items():
             for path_str, value in changes.items():
                 objects = [
                     f'mgmtEventUser s "{trap_username}"',
                     f'mgmtEventSource i {snmp_event_source}',
                     f'mgmtEventType i {snmp_change_type[change_type]}'
                 ]
 
                 if change_type == 'add':
                     objects.append(f'mgmtEventCurrCfg s "{path_str} {value}"')
                 elif change_type == 'delete':
                     objects.append(f'mgmtEventPrevCfg s "{path_str} {value}"')
                 elif change_type == 'change':
                     objects.append(f'mgmtEventPrevCfg s "{path_str} {value[0]}"')
                     objects.append(f'mgmtEventCurrCfg s "{path_str} {value[1]}"')
 
                 cmd(base_cmd + ' '.join(objects))
 
 def state_policy_rule_exists():
     # Determine if state policy rules already exist in nft
     search_str = cmd(f'nft list chain ip filter VYOS_FW_FORWARD')
     return 'VYOS_STATE_POLICY' in search_str
 
 def resync_policy_route():
     # Update policy route as firewall groups were updated
     tmp = run(policy_route_conf_script)
     if tmp > 0:
         Warning('Failed to re-apply policy route configuration!')
 
 def apply(firewall):
     if 'first_install' in firewall:
         run('nfct helper add rpc inet tcp')
         run('nfct helper add rpc inet udp')
         run('nfct helper add tns inet tcp')
 
     install_result = run(f'nft -f {nftables_conf}')
     if install_result == 1:
         raise ConfigError('Failed to apply firewall')
 
     # set fireall group domain-group xxx
     if 'group' in firewall:
         if 'domain_group' in firewall['group']:
             # T970 Enable a resolver (systemd daemon) that checks
             # domain-group addresses and update entries for domains by timeout
             # If router loaded without internet connection or for synchronization
             call('systemctl restart vyos-domain-group-resolve.service')
             for group, group_config in firewall['group']['domain_group'].items():
                 domains = []
-                for address in group_config['address']:
-                    domains.append(address)
+                if group_config.get('address') is not None:
+                    for address in group_config.get('address'):
+                        domains.append(address)
                 # Add elements to domain-group, try to resolve domain => ip
                 # and add elements to nft set
                 ip_dict = get_ips_domains_dict(domains)
                 elements = sum(ip_dict.values(), [])
                 nft_init_set(group)
                 nft_add_set_elements(group, elements)
         else:
             call('systemctl stop vyos-domain-group-resolve.service')
 
     if 'state_policy' in firewall and not state_policy_rule_exists():
         for chain in ['VYOS_FW_FORWARD', 'VYOS_FW_OUTPUT', 'VYOS_FW_LOCAL']:
             cmd(f'nft insert rule ip filter {chain} jump VYOS_STATE_POLICY')
 
         for chain in ['VYOS_FW6_FORWARD', 'VYOS_FW6_OUTPUT', 'VYOS_FW6_LOCAL']:
             cmd(f'nft insert rule ip6 filter {chain} jump VYOS_STATE_POLICY6')
 
     apply_sysfs(firewall)
 
     if firewall['policy_resync']:
         resync_policy_route()
 
     post_apply_trap(firewall)
 
     return None
 
 if __name__ == '__main__':
     try:
         c = get_config()
         verify(c)
         generate(c)
         apply(c)
     except ConfigError as e:
         print(e)
         exit(1)