diff --git a/data/templates/conntrack/nftables-helpers.j2 b/data/templates/conntrack/nftables-helpers.j2
index 433931162..63a0cc855 100644
--- a/data/templates/conntrack/nftables-helpers.j2
+++ b/data/templates/conntrack/nftables-helpers.j2
@@ -1,70 +1,76 @@
 {% macro conntrack_helpers(module_map, modules, ipv4=True) %}
 {% if modules.ftp is vyos_defined %}
     ct helper ftp_tcp {
         type "ftp" protocol tcp;
     }
 {% endif %}
 
 {% if modules.h323 is vyos_defined %}
     ct helper ras_udp {
         type "RAS" protocol udp;
     }
 
     ct helper q931_tcp {
         type "Q.931" protocol tcp;
     }
 {% endif %}
 
 {% if modules.pptp is vyos_defined and ipv4 %}
     ct helper pptp_tcp {
         type "pptp" protocol tcp;
     }
 {% endif %}
 
 {% if modules.nfs is vyos_defined %}
     ct helper rpc_tcp {
         type "rpc" protocol tcp;
     }
 
     ct helper rpc_udp {
         type "rpc" protocol udp;
     }
 {% endif %}
 
+{% if modules.rtsp is vyos_defined and ipv4 %}
+    ct helper rtsp_tcp {
+        type "rtsp" protocol tcp;
+    }
+{% endif %}
+
 {% if modules.sip is vyos_defined %}
     ct helper sip_tcp {
         type "sip" protocol tcp;
     }
 
     ct helper sip_udp {
         type "sip" protocol udp;
     }
 {% endif %}
 
 {% if modules.tftp is vyos_defined %}
     ct helper tftp_udp {
         type "tftp" protocol udp;
     }
 {% endif %}
 
 {% if modules.sqlnet is vyos_defined %}
     ct helper tns_tcp {
         type "tns" protocol tcp;
     }
 {% endif %}
 
     chain VYOS_CT_HELPER {
 {% for module, module_conf in module_map.items() %}
 {%     if modules[module] is vyos_defined %}
 {%         if 'nftables' in module_conf %}
 {%             if module_conf.ipv4 is not vyos_defined or module_conf.ipv4 == ipv4 %}
 {%                 for rule in module_conf.nftables %}
         {{ rule }}
 {%                 endfor %}
 {%             endif %}
 {%         endif %}
 {%     endif %}
 {% endfor %}
         return
     }
 {% endmacro %}
diff --git a/debian/control b/debian/control
index dddc4e14c..c5a60f660 100644
--- a/debian/control
+++ b/debian/control
@@ -1,336 +1,339 @@
 Source: vyos-1x
 Section: contrib/net
 Priority: extra
 Maintainer: VyOS Package Maintainers <maintainers@vyos.net>
 Build-Depends:
   debhelper (>= 9),
   dh-python,
   fakeroot,
   gcc,
   iproute2,
   libvyosconfig0 (>= 0.0.7),
   libzmq3-dev,
   python3 (>= 3.10),
 # For generating command definitions
   python3-lxml,
   python3-xmltodict,
 # For running tests
   python3-coverage,
   python3-netifaces,
   python3-nose,
   python3-jinja2,
   python3-psutil,
   python3-setuptools,
   python3-sphinx,
   quilt,
   whois
 Standards-Version: 3.9.6
 
 Package: vyos-1x
 Architecture: amd64 arm64
 Pre-Depends:
   libnss-tacplus [amd64],
   libpam-tacplus [amd64],
   libpam-radius-auth [amd64]
 Depends:
 ## Fundamentals
   ${python3:Depends} (>= 3.10),
   libvyosconfig0,
   vyatta-bash,
   vyatta-cfg,
   vyos-http-api-tools,
   vyos-utils,
 ## End of Fundamentals
 ## Python libraries used in multiple modules and scripts
   python3,
   python3-cryptography,
   python3-hurry.filesize,
   python3-inotify,
   python3-jinja2,
   python3-jmespath,
   python3-netaddr,
   python3-netifaces,
   python3-paramiko,
   python3-passlib,
   python3-psutil,
   python3-pyhumps,
   python3-pystache,
   python3-pyudev,
   python3-six,
   python3-tabulate,
   python3-voluptuous,
   python3-xmltodict,
   python3-zmq,
 ## End of Python libraries
 ## Basic System services and utilities
   sudo,
   systemd,
   bsdmainutils,
   openssl,
   curl,
   dbus,
   file,
   iproute2 (>= 6.0.0),
   linux-cpupower,
 # ipaddrcheck is widely used in IP value validators
   ipaddrcheck,
   ethtool,
   fdisk,
   lm-sensors,
   procps,
   netplug,
   sed,
   ssl-cert,
   tuned,
   beep,
   wide-dhcpv6-client,
 # Generic colorizer
   grc,
 ## End of System services and utilities
 ## For the installer
 # Image signature verification tool
   minisign,
 # Live filesystem tools
   squashfs-tools,
   fuse-overlayfs,
 ## End installer
   auditd,
   iputils-arping,
   isc-dhcp-client,
 # For "vpn pptp", "vpn l2tp", "vpn sstp", "service ipoe-server"
   accel-ppp,
 # End "vpn pptp", "vpn l2tp", "vpn sstp", "service ipoe-server"
   avahi-daemon,
   conntrack,
   conntrackd,
 ## Conf mode features
 # For "interfaces wireless"
   hostapd,
   hsflowd,
   iw,
   wireless-regdb,
   wpasupplicant (>= 0.6.7),
 # End "interfaces wireless"
 # For "interfaces wwan"
   modemmanager,
   usb-modeswitch,
   libqmi-utils,
 # End "interfaces wwan"
 # For "interfaces openvpn"
   openvpn,
   openvpn-auth-ldap,
   openvpn-auth-radius,
   openvpn-otp,
   libpam-google-authenticator,
 # End "interfaces openvpn"
 # For "interfaces wireguard"
   wireguard-tools,
   qrencode,
 # End "interfaces wireguard"
 # For "interfaces pppoe"
   pppoe,
 # End "interfaces pppoe"
 # For "interfaces sstpc"
   sstp-client,
 # End "interfaces sstpc"
 # For "protocols *"
   frr (>= 7.5),
   frr-pythontools,
   frr-rpki-rtrlib,
   frr-snmp,
 # End "protocols *"
 # For "protocols nhrp" (part of DMVPN)
   opennhrp,
 # End "protocols nhrp"
 # For "protocols igmp-proxy"
   igmpproxy,
 # End "protocols igmp-proxy"
 # For "pki"
   certbot,
 # End "pki"
 # For "service console-server"
   conserver-client,
   conserver-server,
   console-data,
   dropbear,
 # End "service console-server"
 # For "service aws glb"
   aws-gwlbtun,
 # For "service dns dynamic"
   ddclient (>= 3.11.1),
 # End "service dns dynamic"
 # # For "service ids"
   fastnetmon [amd64],
 # End "service ids"
 # # For "service ndp-proxy"
   ndppd,
 # End "service ndp-proxy"
 # For "service router-advert"
   radvd,
 # End "service route-advert"
 # For "high-availability reverse-proxy"
   haproxy,
 # End "high-availability reverse-proxy"
 # For "service dhcp-relay"
   isc-dhcp-relay,
 # For "service dhcp-server"
   kea,
 # End "service dhcp-server"
 # For "service lldp"
   lldpd,
 # End "service lldp"
 # For "service https"
   nginx-light,
 # End "service https"
 # For "service ssh"
   openssh-server,
   sshguard,
 # End "service ssh"
 # For "service salt-minion"
   salt-minion,
 # End "service salt-minion"
 # For "service snmp"
   snmp,
   snmpd,
 # End "service snmp"
 # For "service upnp"
   miniupnpd-nftables,
 # End "service upnp"
 # For "service webproxy"
   squid,
   squidclient,
   squidguard,
 # End "service webproxy"
 # For "service monitoring telegraf"
   telegraf (>= 1.20),
 # End "service monitoring telegraf"
 # For "service monitoring zabbix-agent"
   zabbix-agent2,
 # End "service monitoring zabbix-agent"
 # For "service tftp-server"
   tftpd-hpa,
 # End "service tftp-server"
 # For "service dns forwarding"
   pdns-recursor,
 # End "service dns forwarding"
 # For "service sla owamp"
   owamp-client,
   owamp-server,
 # End "service sla owamp"
 # For "service sla twamp"
   twamp-client,
   twamp-server,
 # End "service sla twamp"
 # For "service broadcast-relay"
   udp-broadcast-relay,
 # End "service broadcast-relay"
 # For "high-availability vrrp"
   keepalived (>=2.0.5),
 # End "high-availability-vrrp"
 # For "system task-scheduler"
   cron,
 # End "system task-scheduler"
 # For "system lcd"
   lcdproc,
   lcdproc-extra-drivers,
 # End "system lcd"
 # For "system config-management commit-archive"
   git,
 # End "system config-management commit-archive"
 # For firewall
   libndp-tools,
   libnetfilter-conntrack3,
   libnfnetlink0,
   nfct,
   nftables (>= 0.9.3),
 # For "vpn ipsec"
   strongswan (>= 5.9),
   strongswan-swanctl (>= 5.9),
   charon-systemd,
   libcharon-extra-plugins (>=5.9),
   libcharon-extauth-plugins (>=5.9),
   libstrongswan-extra-plugins (>=5.9),
   libstrongswan-standard-plugins (>=5.9),
   python3-vici (>= 5.7.2),
 # End "vpn ipsec"
 # For "nat64"
   jool,
 # End "nat64"
+# For "system conntrack modules rtsp"
+  nat-rtsp,
+# End "system conntrack modules rtsp"
 # For "system ntp"
   chrony,
 # End "system ntp"
 # For "vpn openconnect"
   ocserv,
 # End "vpn openconnect"
 # For "system flow-accounting"
   pmacct (>= 1.6.0),
 # End "system flow-accounting"
 # For container
   podman,
   netavark,
   aardvark-dns,
 # iptables is only used for containers now, not the the firewall CLI
   iptables,
 # End container
 ## End Configuration mode
 ## Operational mode
 # Used for hypervisor model in "run show version"
   hvinfo,
 # For "run traceroute"
   traceroute,
 # For "run monitor traffic"
   tcpdump,
 # End "run monitor traffic"
 # For "show hardware dmi"
   dmidecode,
 # For "run show hardware storage smart"
   smartmontools,
 # For "run show hardware scsi"
   lsscsi,
 # For "run show hardware pci"
   pciutils,
 # For "show hardware usb"
   usbutils,
 # For "run show hardware storage nvme"
   nvme-cli,
 # For "run monitor bandwidth-test"
   iperf,
   iperf3,
 # End "run monitor bandwidth-test"
 # For "run wake-on-lan"
   etherwake,
 # For "run force ipv6-nd"
   ndisc6,
 # For "run monitor bandwidth"
   bmon,
 # End Operational mode
 ## TPM tools
   cryptsetup,
   tpm2-tools,
 ## End TPM tools
 ## Optional utilities
   easy-rsa,
   tcptraceroute,
   mtr-tiny,
   telnet,
   stunnel4,
   uidmap
 ## End optional utilities
 Description: VyOS configuration scripts and data
  VyOS configuration scripts, interface definitions, and everything
 
 Package: vyos-1x-vmware
 Architecture: amd64
 Depends:
  vyos-1x,
  open-vm-tools
 Description: VyOS configuration scripts and data for VMware
  Adds configuration files required for VyOS running on VMware hosts.
 
 Package: vyos-1x-smoketest
 Architecture: all
 Depends:
  skopeo,
  snmp,
  vyos-1x
 Description: VyOS build sanity checking toolkit
diff --git a/interface-definitions/include/firewall/conntrack-helper.xml.i b/interface-definitions/include/firewall/conntrack-helper.xml.i
index ee17f2c61..3ca1a0353 100644
--- a/interface-definitions/include/firewall/conntrack-helper.xml.i
+++ b/interface-definitions/include/firewall/conntrack-helper.xml.i
@@ -1,42 +1,46 @@
 <!-- include start from firewall/conntrack-helper.xml.i -->
 <leafNode name="conntrack-helper">
   <properties>
     <help>Match related traffic from conntrack helpers</help>
     <completionHelp>
       <list>ftp h323 pptp nfs sip tftp sqlnet</list>
     </completionHelp>
     <valueHelp>
       <format>ftp</format>
       <description>Related traffic from FTP helper</description>
     </valueHelp>
     <valueHelp>
       <format>h323</format>
       <description>Related traffic from H.323 helper</description>
     </valueHelp>
     <valueHelp>
       <format>pptp</format>
       <description>Related traffic from PPTP helper</description>
     </valueHelp>
     <valueHelp>
       <format>nfs</format>
       <description>Related traffic from NFS helper</description>
     </valueHelp>
+    <valueHelp>
+      <format>rtsp</format>
+      <description>Related traffic from RTSP helper</description>
+    </valueHelp>
     <valueHelp>
       <format>sip</format>
       <description>Related traffic from SIP helper</description>
     </valueHelp>
     <valueHelp>
       <format>tftp</format>
       <description>Related traffic from TFTP helper</description>
     </valueHelp>
     <valueHelp>
       <format>sqlnet</format>
       <description>Related traffic from SQLNet helper</description>
     </valueHelp>
     <constraint>
-      <regex>(ftp|h323|pptp|nfs|sip|tftp|sqlnet)</regex>
+      <regex>(ftp|h323|pptp|nfs|rtsp|sip|tftp|sqlnet)</regex>
     </constraint>
     <multi/>
   </properties>
 </leafNode>
 <!-- include end -->
diff --git a/interface-definitions/system_conntrack.xml.in b/interface-definitions/system_conntrack.xml.in
index a348097cc..219c6e28e 100644
--- a/interface-definitions/system_conntrack.xml.in
+++ b/interface-definitions/system_conntrack.xml.in
@@ -1,513 +1,519 @@
 <?xml version="1.0"?>
 <interfaceDefinition>
   <node name="system">
     <children>
       <node name="conntrack" owner="${vyos_conf_scripts_dir}/system_conntrack.py">
         <properties>
           <help>Connection Tracking Engine Options</help>
           <!-- Before NAT and conntrack-sync are configured -->
           <priority>218</priority>
         </properties>
         <children>
           <leafNode name="flow-accounting">
             <properties>
               <help>Enable connection tracking flow accounting</help>
               <valueless/>
             </properties>
           </leafNode>
           <leafNode name="expect-table-size">
             <properties>
               <help>Size of connection tracking expect table</help>
               <valueHelp>
                 <format>u32:1-50000000</format>
                 <description>Number of entries allowed in connection tracking expect table</description>
               </valueHelp>
               <constraint>
                 <validator name="numeric" argument="--range 1-50000000"/>
               </constraint>
             </properties>
             <defaultValue>2048</defaultValue>
           </leafNode>
           <leafNode name="hash-size">
             <properties>
               <help>Hash size for connection tracking table</help>
               <valueHelp>
                 <format>u32:1-50000000</format>
                 <description>Size of hash to use for connection tracking table</description>
               </valueHelp>
               <constraint>
                 <validator name="numeric" argument="--range 1-50000000"/>
               </constraint>
             </properties>
             <defaultValue>32768</defaultValue>
           </leafNode>
           <node name="ignore">
             <properties>
               <help>Customized rules to ignore selective connection tracking</help>
             </properties>
             <children>
               <node name="ipv4">
                 <properties>
                   <help>IPv4 rules</help>
                 </properties>
                 <children>
                   <tagNode name="rule">
                     <properties>
                       <help>Rule number</help>
                       <valueHelp>
                         <format>u32:1-999999</format>
                         <description>Number of conntrack ignore rule</description>
                       </valueHelp>
                       <constraint>
                         <validator name="numeric" argument="--range 1-999999"/>
                       </constraint>
                       <constraintErrorMessage>Ignore rule number must be between 1 and 999999</constraintErrorMessage>
                     </properties>
                     <children>
                       #include <include/generic-description.xml.i>
                       <node name="destination">
                         <properties>
                           <help>Destination parameters</help>
                         </properties>
                         <children>
                           #include <include/firewall/source-destination-group-ipv4.xml.i>
                           #include <include/nat-address.xml.i>
                           #include <include/nat-port.xml.i>
                         </children>
                       </node>
                       <leafNode name="inbound-interface">
                         <properties>
                           <help>Interface to ignore connections tracking on</help>
                           <completionHelp>
                             <list>any</list>
                             <script>${vyos_completion_dir}/list_interfaces</script>
                           </completionHelp>
                         </properties>
                       </leafNode>
                       #include <include/ip-protocol.xml.i>
                       <leafNode name="protocol">
                         <properties>
                           <help>Protocol to match (protocol name, number, or "all")</help>
                           <completionHelp>
                             <script>${vyos_completion_dir}/list_protocols.sh</script>
                             <list>all tcp_udp</list>
                           </completionHelp>
                           <valueHelp>
                             <format>all</format>
                             <description>All IP protocols</description>
                           </valueHelp>
                           <valueHelp>
                             <format>tcp_udp</format>
                             <description>Both TCP and UDP</description>
                           </valueHelp>
                           <valueHelp>
                             <format>u32:0-255</format>
                             <description>IP protocol number</description>
                           </valueHelp>
                           <valueHelp>
                             <format>&lt;protocol&gt;</format>
                             <description>IP protocol name</description>
                           </valueHelp>
                           <valueHelp>
                             <format>!&lt;protocol&gt;</format>
                             <description>IP protocol name</description>
                           </valueHelp>
                           <constraint>
                             <validator name="ip-protocol"/>
                           </constraint>
                         </properties>
                       </leafNode>
                       <node name="source">
                         <properties>
                           <help>Source parameters</help>
                         </properties>
                         <children>
                           #include <include/firewall/source-destination-group-ipv4.xml.i>
                           #include <include/nat-address.xml.i>
                           #include <include/nat-port.xml.i>
                         </children>
                       </node>
                       #include <include/firewall/tcp-flags.xml.i>
                     </children>
                   </tagNode>
                 </children>
               </node>
               <node name="ipv6">
                 <properties>
                   <help>IPv6 rules</help>
                 </properties>
                 <children>
                   <tagNode name="rule">
                     <properties>
                       <help>Rule number</help>
                       <valueHelp>
                         <format>u32:1-999999</format>
                         <description>Number of conntrack ignore rule</description>
                       </valueHelp>
                       <constraint>
                         <validator name="numeric" argument="--range 1-999999"/>
                       </constraint>
                       <constraintErrorMessage>Ignore rule number must be between 1 and 999999</constraintErrorMessage>
                     </properties>
                     <children>
                       #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/nat-port.xml.i>
                         </children>
                       </node>
                       <leafNode name="inbound-interface">
                         <properties>
                           <help>Interface to ignore connections tracking on</help>
                           <completionHelp>
                             <list>any</list>
                             <script>${vyos_completion_dir}/list_interfaces</script>
                           </completionHelp>
                         </properties>
                       </leafNode>
                       #include <include/ip-protocol.xml.i>
                       <leafNode name="protocol">
                         <properties>
                           <help>Protocol to match (protocol name, number, or "all")</help>
                           <completionHelp>
                             <script>${vyos_completion_dir}/list_protocols.sh</script>
                             <list>all tcp_udp</list>
                           </completionHelp>
                           <valueHelp>
                             <format>all</format>
                             <description>All IP protocols</description>
                           </valueHelp>
                           <valueHelp>
                             <format>tcp_udp</format>
                             <description>Both TCP and UDP</description>
                           </valueHelp>
                           <valueHelp>
                             <format>u32:0-255</format>
                             <description>IP protocol number</description>
                           </valueHelp>
                           <valueHelp>
                             <format>&lt;protocol&gt;</format>
                             <description>IP protocol name</description>
                           </valueHelp>
                           <valueHelp>
                             <format>!&lt;protocol&gt;</format>
                             <description>IP protocol name</description>
                           </valueHelp>
                           <constraint>
                             <validator name="ip-protocol"/>
                           </constraint>
                         </properties>
                       </leafNode>
                       <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/nat-port.xml.i>
                         </children>
                       </node>
                       #include <include/firewall/tcp-flags.xml.i>
                     </children>
                   </tagNode>
                 </children>
               </node>
 
             </children>
           </node>
           <node name="log">
             <properties>
               <help>Log connection tracking events per protocol</help>
             </properties>
             <children>
               <node name="icmp">
                 <properties>
                   <help>Log connection tracking events for ICMP</help>
                 </properties>
                 <children>
                   #include <include/conntrack/log-common.xml.i>
                 </children>
               </node>
               <node name="other">
                 <properties>
                   <help>Log connection tracking events for all protocols other than TCP, UDP and ICMP</help>
                 </properties>
                 <children>
                   #include <include/conntrack/log-common.xml.i>
                 </children>
               </node>
               <node name="tcp">
                 <properties>
                   <help>Log connection tracking events for TCP</help>
                 </properties>
                 <children>
                   #include <include/conntrack/log-common.xml.i>
                 </children>
               </node>
               <node name="udp">
                 <properties>
                   <help>Log connection tracking events for UDP</help>
                 </properties>
                 <children>
                   #include <include/conntrack/log-common.xml.i>
                 </children>
               </node>
             </children>
           </node>
           <node name="modules">
             <properties>
               <help>Connection tracking modules</help>
             </properties>
             <children>
               <leafNode name="ftp">
                 <properties>
                   <help>FTP connection tracking</help>
                   <valueless/>
                 </properties>
               </leafNode>
               <leafNode name="h323">
                 <properties>
                   <help>H.323 connection tracking</help>
                   <valueless/>
                 </properties>
               </leafNode>
               <leafNode name="nfs">
                 <properties>
                   <help>NFS connection tracking</help>
                   <valueless/>
                 </properties>
               </leafNode>
               <leafNode name="pptp">
                 <properties>
                   <help>PPTP connection tracking</help>
                   <valueless/>
                 </properties>
               </leafNode>
+              <leafNode name="rtsp">
+                <properties>
+                  <help>RTSP connection tracking</help>
+                  <valueless/>
+                </properties>
+              </leafNode>
               <leafNode name="sip">
                 <properties>
                   <help>SIP connection tracking</help>
                   <valueless/>
                 </properties>
               </leafNode>
               <leafNode name="sqlnet">
                 <properties>
                   <help>SQLnet connection tracking</help>
                   <valueless/>
                 </properties>
               </leafNode>
               <leafNode name="tftp">
                 <properties>
                   <help>TFTP connection tracking</help>
                   <valueless/>
                 </properties>
               </leafNode>
             </children>
           </node>
           <leafNode name="table-size">
             <properties>
               <help>Size of connection tracking table</help>
               <valueHelp>
                 <format>u32:1-50000000</format>
                 <description>Number of entries allowed in connection tracking table</description>
               </valueHelp>
               <constraint>
                 <validator name="numeric" argument="--range 1-50000000"/>
               </constraint>
             </properties>
             <defaultValue>262144</defaultValue>
           </leafNode>
           <node name="tcp">
             <properties>
               <help>TCP options</help>
             </properties>
             <children>
               <leafNode name="half-open-connections">
                 <properties>
                   <help>Maximum number of TCP half-open connections</help>
                   <valueHelp>
                     <format>u32:1-2147483647</format>
                     <description>Generic connection timeout in seconds</description>
                   </valueHelp>
                   <constraint>
                     <validator name="numeric" argument="--range 1-2147483647"/>
                   </constraint>
                 </properties>
                 <defaultValue>512</defaultValue>
               </leafNode>
               <leafNode name="loose">
                 <properties>
                   <help>Policy to track previously established connections</help>
                   <completionHelp>
                     <list>enable disable</list>
                   </completionHelp>
                   <valueHelp>
                     <format>enable</format>
                     <description>Allow tracking of previously established connections</description>
                   </valueHelp>
                   <valueHelp>
                     <format>disable</format>
                     <description>Do not allow tracking of previously established connections</description>
                   </valueHelp>
                   <constraint>
                     <regex>(enable|disable)</regex>
                   </constraint>
                 </properties>
                 <defaultValue>enable</defaultValue>
               </leafNode>
               <leafNode name="max-retrans">
                 <properties>
                   <help>Maximum number of packets that can be retransmitted without received an ACK</help>
                   <valueHelp>
                     <format>u32:1-255</format>
                     <description>Number of packets to be retransmitted</description>
                   </valueHelp>
                   <constraint>
                     <validator name="numeric" argument="--range 1-255"/>
                   </constraint>
                 </properties>
                 <defaultValue>3</defaultValue>
               </leafNode>
             </children>
           </node>
           <node name="timeout">
             <properties>
               <help>Connection timeout options</help>
             </properties>
             <children>
               <node name="custom">
                 <properties>
                   <help>Define custom timeouts per connection</help>
                 </properties>
                 <children>
                   <node name="ipv4">
                     <properties>
                       <help>IPv4 rules</help>
                     </properties>
                     <children>
                       <tagNode name="rule">
                         <properties>
                           <help>Rule number</help>
                           <valueHelp>
                             <format>u32:1-999999</format>
                             <description>Number of conntrack rule</description>
                           </valueHelp>
                           <constraint>
                             <validator name="numeric" argument="--range 1-999999"/>
                           </constraint>
                           <constraintErrorMessage>Ignore rule number must be between 1 and 999999</constraintErrorMessage>
                         </properties>
                         <children>
                           #include <include/generic-description.xml.i>
                           <node name="destination">
                             <properties>
                               <help>Destination parameters</help>
                             </properties>
                             <children>
                               #include <include/nat-address.xml.i>
                               #include <include/nat-port.xml.i>
                             </children>
                           </node>
                           <leafNode name="inbound-interface">
                             <properties>
                               <help>Interface to ignore connections tracking on</help>
                               <completionHelp>
                                 <list>any</list>
                                 <script>${vyos_completion_dir}/list_interfaces</script>
                               </completionHelp>
                             </properties>
                           </leafNode>
                           <node name="protocol">
                             <properties>
                               <help>Customize protocol specific timers, one protocol configuration per rule</help>
                             </properties>
                             <children>
                               #include <include/conntrack/timeout-custom-protocols.xml.i>
                             </children>
                           </node>
                           <node name="source">
                             <properties>
                               <help>Source parameters</help>
                             </properties>
                             <children>
                               #include <include/nat-address.xml.i>
                               #include <include/nat-port.xml.i>
                             </children>
                           </node>
                         </children>
                       </tagNode>
                     </children>
                   </node>
                   <node name="ipv6">
                     <properties>
                       <help>IPv6 rules</help>
                     </properties>
                     <children>
                       <tagNode name="rule">
                         <properties>
                           <help>Rule number</help>
                           <valueHelp>
                             <format>u32:1-999999</format>
                             <description>Number of conntrack rule</description>
                           </valueHelp>
                           <constraint>
                             <validator name="numeric" argument="--range 1-999999"/>
                           </constraint>
                           <constraintErrorMessage>Ignore rule number must be between 1 and 999999</constraintErrorMessage>
                         </properties>
                         <children>
                           #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/nat-port.xml.i>
                             </children>
                           </node>
                           <leafNode name="inbound-interface">
                             <properties>
                               <help>Interface to ignore connections tracking on</help>
                               <completionHelp>
                                 <list>any</list>
                                 <script>${vyos_completion_dir}/list_interfaces</script>
                               </completionHelp>
                             </properties>
                           </leafNode>
                           <node name="protocol">
                             <properties>
                               <help>Customize protocol specific timers, one protocol configuration per rule</help>
                             </properties>
                             <children>
                               #include <include/conntrack/timeout-custom-protocols.xml.i>
                             </children>
                           </node>
                           <node name="source">
                             <properties>
                               <help>Source parameters</help>
                             </properties>
                             <children>
                               #include <include/firewall/address-ipv6.xml.i>
                               #include <include/nat-port.xml.i>
                             </children>
                           </node>
                         </children>
                       </tagNode>
                     </children>
                   </node>
                 </children>
               </node>
               #include <include/conntrack/timeout-common-protocols.xml.i>
             </children>
           </node>
         </children>
       </node>
     </children>
   </node>
 </interfaceDefinition>
diff --git a/smoketest/scripts/cli/test_system_conntrack.py b/smoketest/scripts/cli/test_system_conntrack.py
index f00626b3d..2d76da145 100755
--- a/smoketest/scripts/cli/test_system_conntrack.py
+++ b/smoketest/scripts/cli/test_system_conntrack.py
@@ -1,341 +1,345 @@
 #!/usr/bin/env python3
 #
 # 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
 # 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
 import unittest
 
 from base_vyostest_shim import VyOSUnitTestSHIM
 
 from vyos.firewall import find_nftables_rule
 from vyos.utils.file import read_file
 
 base_path = ['system', 'conntrack']
 
 def get_sysctl(parameter):
     tmp = parameter.replace(r'.', r'/')
     return read_file(f'/proc/sys/{tmp}')
 
 class TestSystemConntrack(VyOSUnitTestSHIM.TestCase):
     @classmethod
     def setUpClass(cls):
         super(TestSystemConntrack, cls).setUpClass()
 
         # ensure we can also run this test on a live system - so lets clean
         # out the current configuration :)
         cls.cli_delete(cls, base_path)
 
     def tearDown(self):
         self.cli_delete(base_path)
         self.cli_commit()
 
     def test_conntrack_options(self):
         conntrack_config = {
             'net.netfilter.nf_conntrack_expect_max' : {
                 'cli'           : ['expect-table-size'],
                 'test_value'    : '8192',
                 'default_value' : '2048',
             },
             'net.nf_conntrack_max' :{
                 'cli'           : ['table-size'],
                 'test_value'    : '500000',
                 'default_value' : '262144',
             },
             'net.ipv4.tcp_max_syn_backlog' :{
                 'cli'           : ['tcp', 'half-open-connections'],
                 'test_value'    : '2048',
                 'default_value' : '512',
             },
             'net.netfilter.nf_conntrack_tcp_loose' :{
                 'cli'           : ['tcp', 'loose'],
                 'test_value'    : 'disable',
                 'default_value' : '1',
             },
             'net.netfilter.nf_conntrack_tcp_max_retrans' :{
                 'cli'           : ['tcp', 'max-retrans'],
                 'test_value'    : '128',
                 'default_value' : '3',
             },
             'net.netfilter.nf_conntrack_icmp_timeout' :{
                 'cli'           : ['timeout', 'icmp'],
                 'test_value'    : '180',
                 'default_value' : '30',
             },
             'net.netfilter.nf_conntrack_generic_timeout' :{
                 'cli'           : ['timeout', 'other'],
                 'test_value'    : '1200',
                 'default_value' : '600',
             },
             'net.netfilter.nf_conntrack_tcp_timeout_close_wait' :{
                 'cli'           : ['timeout', 'tcp', 'close-wait'],
                 'test_value'    : '30',
                 'default_value' : '60',
             },
             'net.netfilter.nf_conntrack_tcp_timeout_close' :{
                 'cli'           : ['timeout', 'tcp', 'close'],
                 'test_value'    : '20',
                 'default_value' : '10',
             },
             'net.netfilter.nf_conntrack_tcp_timeout_established' :{
                 'cli'           : ['timeout', 'tcp', 'established'],
                 'test_value'    : '1000',
                 'default_value' : '432000',
             },
             'net.netfilter.nf_conntrack_tcp_timeout_fin_wait' :{
                 'cli'           : ['timeout', 'tcp', 'fin-wait'],
                 'test_value'    : '240',
                 'default_value' : '120',
             },
             'net.netfilter.nf_conntrack_tcp_timeout_last_ack' :{
                 'cli'           : ['timeout', 'tcp', 'last-ack'],
                 'test_value'    : '300',
                 'default_value' : '30',
             },
             'net.netfilter.nf_conntrack_tcp_timeout_syn_recv' :{
                 'cli'           : ['timeout', 'tcp', 'syn-recv'],
                 'test_value'    : '100',
                 'default_value' : '60',
             },
             'net.netfilter.nf_conntrack_tcp_timeout_syn_sent' :{
                 'cli'           : ['timeout', 'tcp', 'syn-sent'],
                 'test_value'    : '300',
                 'default_value' : '120',
             },
             'net.netfilter.nf_conntrack_tcp_timeout_time_wait' :{
                 'cli'           : ['timeout', 'tcp', 'time-wait'],
                 'test_value'    : '303',
                 'default_value' : '120',
             },
             'net.netfilter.nf_conntrack_udp_timeout' :{
                 'cli'           : ['timeout', 'udp', 'other'],
                 'test_value'    : '90',
                 'default_value' : '30',
             },
             'net.netfilter.nf_conntrack_udp_timeout_stream' :{
                 'cli'           : ['timeout', 'udp', 'stream'],
                 'test_value'    : '200',
                 'default_value' : '180',
             },
         }
 
         for parameter, parameter_config in conntrack_config.items():
             self.cli_set(base_path + parameter_config['cli'] + [parameter_config['test_value']])
 
         # commit changes
         self.cli_commit()
 
         # validate configuration
         for parameter, parameter_config in conntrack_config.items():
             tmp = parameter_config['test_value']
             # net.netfilter.nf_conntrack_tcp_loose has a fancy "disable" value,
             # make this work
             if tmp == 'disable':
                 tmp = '0'
             self.assertEqual(get_sysctl(f'{parameter}'), tmp)
 
         # delete all configuration options and revert back to defaults
         self.cli_delete(base_path)
         self.cli_commit()
 
         # validate configuration
         for parameter, parameter_config in conntrack_config.items():
             self.assertEqual(get_sysctl(f'{parameter}'), parameter_config['default_value'])
 
 
     def test_conntrack_module_enable(self):
         # conntrack helper modules are disabled by default
         modules = {
             'ftp': {
                 'driver': ['nf_nat_ftp', 'nf_conntrack_ftp'],
                 'nftables': ['ct helper set "ftp_tcp"']
             },
             'h323': {
                 'driver': ['nf_nat_h323', 'nf_conntrack_h323'],
                 'nftables': ['ct helper set "ras_udp"',
                              'ct helper set "q931_tcp"']
             },
             'nfs': {
                 'nftables': ['ct helper set "rpc_tcp"',
                              'ct helper set "rpc_udp"']
             },
             'pptp': {
                 'driver': ['nf_nat_pptp', 'nf_conntrack_pptp'],
                 'nftables': ['ct helper set "pptp_tcp"']
-             },
+            },
+            'rtsp': {
+                'driver': ['nf_nat_rtsp', 'nf_conntrack_rtsp'],
+                'nftables': ['ct helper set "rtsp_tcp"']
+            },
             'sip': {
                 'driver': ['nf_nat_sip', 'nf_conntrack_sip'],
                 'nftables': ['ct helper set "sip_tcp"',
                              'ct helper set "sip_udp"']
-             },
+            },
             'sqlnet': {
                 'nftables': ['ct helper set "tns_tcp"']
             },
             'tftp': {
                 'driver': ['nf_nat_tftp', 'nf_conntrack_tftp'],
                 'nftables': ['ct helper set "tftp_udp"']
              },
         }
 
         # load modules
         for module in modules:
             self.cli_set(base_path + ['modules', module])
 
         # commit changes
         self.cli_commit()
 
         # verify modules are loaded on the system
         for module, module_options in modules.items():
             if 'driver' in module_options:
                 for driver in module_options['driver']:
                     self.assertTrue(os.path.isdir(f'/sys/module/{driver}'))
             if 'nftables' in module_options:
                 for rule in module_options['nftables']:
                     self.assertTrue(find_nftables_rule('ip vyos_conntrack', 'VYOS_CT_HELPER', [rule]) != None)
 
         # unload modules
         for module in modules:
             self.cli_delete(base_path + ['modules', module])
 
         # commit changes
         self.cli_commit()
 
         # verify modules are not loaded on the system
         for module, module_options in modules.items():
             if 'driver' in module_options:
                 for driver in module_options['driver']:
                     self.assertFalse(os.path.isdir(f'/sys/module/{driver}'))
             if 'nftables' in module_options:
                 for rule in module_options['nftables']:
                     self.assertTrue(find_nftables_rule('ip vyos_conntrack', 'VYOS_CT_HELPER', [rule]) == None)
 
     def test_conntrack_hash_size(self):
         hash_size = '65536'
         hash_size_default = '32768'
 
         self.cli_set(base_path + ['hash-size', hash_size])
 
         # commit changes
         self.cli_commit()
 
         # verify new configuration - only effective after reboot, but
         # a valid config file is sufficient
         tmp = read_file('/etc/modprobe.d/vyatta_nf_conntrack.conf')
         self.assertIn(hash_size, tmp)
 
         # Test default value by deleting the configuration
         self.cli_delete(base_path + ['hash-size'])
 
         # commit changes
         self.cli_commit()
 
         # verify new configuration - only effective after reboot, but
         # a valid config file is sufficient
         tmp = read_file('/etc/modprobe.d/vyatta_nf_conntrack.conf')
         self.assertIn(hash_size_default, tmp)
 
     def test_conntrack_ignore(self):
         address_group = 'conntracktest'
         address_group_member = '192.168.0.1'
         ipv6_address_group = 'conntracktest6'
         ipv6_address_group_member = 'dead:beef::1'
 
         self.cli_set(['firewall', 'group', 'address-group', address_group, 'address', address_group_member])
         self.cli_set(['firewall', 'group', 'ipv6-address-group', ipv6_address_group, 'address', ipv6_address_group_member])
 
         self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '1', 'source', 'address', '192.0.2.1'])
         self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '1', 'destination', 'address', '192.0.2.2'])
         self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '1', 'destination', 'port', '22'])
         self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '1', 'protocol', 'tcp'])
         self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '1', 'tcp', 'flags', 'syn'])
 
         self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '2', 'source', 'address', '192.0.2.1'])
         self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '2', 'destination', 'group', 'address-group', address_group])
 
         self.cli_set(base_path + ['ignore', 'ipv6', 'rule', '11', 'source', 'address', 'fe80::1'])
         self.cli_set(base_path + ['ignore', 'ipv6', 'rule', '11', 'destination', 'address', 'fe80::2'])
         self.cli_set(base_path + ['ignore', 'ipv6', 'rule', '11', 'destination', 'port', '22'])
         self.cli_set(base_path + ['ignore', 'ipv6', 'rule', '11', 'protocol', 'tcp'])
 
         self.cli_set(base_path + ['ignore', 'ipv6', 'rule', '12', 'source', 'address', 'fe80::1'])
         self.cli_set(base_path + ['ignore', 'ipv6', 'rule', '12', 'destination', 'group', 'address-group', ipv6_address_group])
 
         self.cli_set(base_path + ['ignore', 'ipv6', 'rule', '13', 'source', 'address', 'fe80::1'])
         self.cli_set(base_path + ['ignore', 'ipv6', 'rule', '13', 'destination', 'address', '!fe80::3'])
 
         self.cli_commit()
 
         nftables_search = [
             ['ip saddr 192.0.2.1', 'ip daddr 192.0.2.2', 'tcp dport 22', 'tcp flags & syn == syn', 'notrack'],
             ['ip saddr 192.0.2.1', 'ip daddr @A_conntracktest', 'notrack']
         ]
 
         nftables6_search = [
             ['ip6 saddr fe80::1', 'ip6 daddr fe80::2', 'tcp dport 22', 'notrack'],
             ['ip6 saddr fe80::1', 'ip6 daddr @A6_conntracktest6', 'notrack'],
             ['ip6 saddr fe80::1', 'ip6 daddr != fe80::3', 'notrack']
         ]
 
         self.verify_nftables(nftables_search, 'ip vyos_conntrack')
         self.verify_nftables(nftables6_search, 'ip6 vyos_conntrack')
 
         self.cli_delete(['firewall'])
 
     def test_conntrack_timeout_custom(self):
 
         self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '1', 'source', 'address', '192.0.2.1'])
         self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '1', 'destination', 'address', '192.0.2.2'])
         self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '1', 'destination', 'port', '22'])
         self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '1', 'protocol', 'tcp', 'syn-sent', '77'])
         self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '1', 'protocol', 'tcp', 'close', '88'])
         self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '1', 'protocol', 'tcp', 'established', '99'])
 
         self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '2', 'inbound-interface', 'eth1'])
         self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '2', 'source', 'address', '198.51.100.1'])
         self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '2', 'protocol', 'udp', 'unreplied', '55'])
 
         self.cli_set(base_path + ['timeout', 'custom', 'ipv6', 'rule', '1', 'source', 'address', '2001:db8::1'])
         self.cli_set(base_path + ['timeout', 'custom', 'ipv6', 'rule', '1', 'inbound-interface', 'eth2'])
         self.cli_set(base_path + ['timeout', 'custom', 'ipv6', 'rule', '1', 'protocol', 'tcp', 'time-wait', '22'])
         self.cli_set(base_path + ['timeout', 'custom', 'ipv6', 'rule', '1', 'protocol', 'tcp', 'last-ack', '33'])
 
         self.cli_commit()
 
         nftables_search = [
             ['ct timeout ct-timeout-1 {'],
             ['protocol tcp'],
             ['policy = { syn_sent : 1m17s, established : 1m39s, close : 1m28s }'],
             ['ct timeout ct-timeout-2 {'],
             ['protocol udp'],
             ['policy = { unreplied : 55s }'],
             ['chain VYOS_CT_TIMEOUT {'],
             ['ip saddr 192.0.2.1', 'ip daddr 192.0.2.2', 'tcp dport 22', 'ct timeout set "ct-timeout-1"'],
             ['iifname "eth1"', 'meta l4proto udp', 'ip saddr 198.51.100.1', 'ct timeout set "ct-timeout-2"']
         ]
 
         nftables6_search = [
             ['ct timeout ct-timeout-1 {'],
             ['protocol tcp'],
             ['policy = { last_ack : 33s, time_wait : 22s }'],
             ['chain VYOS_CT_TIMEOUT {'],
             ['iifname "eth2"', 'meta l4proto tcp', 'ip6 saddr 2001:db8::1', 'ct timeout set "ct-timeout-1"']
         ]
 
         self.verify_nftables(nftables_search, 'ip vyos_conntrack')
         self.verify_nftables(nftables6_search, 'ip6 vyos_conntrack')
 
         self.cli_delete(['firewall'])
 if __name__ == '__main__':
     unittest.main(verbosity=2)
diff --git a/src/conf_mode/system_conntrack.py b/src/conf_mode/system_conntrack.py
index 2a55daed4..a1472aaaa 100755
--- a/src/conf_mode/system_conntrack.py
+++ b/src/conf_mode/system_conntrack.py
@@ -1,247 +1,252 @@
 #!/usr/bin/env python3
 #
 # 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
 # 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 sys import exit
 
 from vyos.config import Config
 from vyos.configdep import set_dependents, call_dependents
 from vyos.utils.process import process_named_running
 from vyos.utils.dict import dict_search
 from vyos.utils.dict import dict_search_args
 from vyos.utils.dict import dict_search_recursive
 from vyos.utils.process import cmd
 from vyos.utils.process import rc_cmd
 from vyos.utils.process import run
 from vyos.template import render
 from vyos import ConfigError
 from vyos import airbag
 airbag.enable()
 
 conntrack_config = r'/etc/modprobe.d/vyatta_nf_conntrack.conf'
 sysctl_file = r'/run/sysctl/10-vyos-conntrack.conf'
 nftables_ct_file = r'/run/nftables-ct.conf'
 
 # Every ALG (Application Layer Gateway) consists of either a Kernel Object
 # also called a Kernel Module/Driver or some rules present in iptables
 module_map = {
     'ftp': {
         'ko': ['nf_nat_ftp', 'nf_conntrack_ftp'],
         'nftables': ['tcp dport {21} ct helper set "ftp_tcp" return']
     },
     'h323': {
         'ko': ['nf_nat_h323', 'nf_conntrack_h323'],
         'nftables': ['udp dport {1719} ct helper set "ras_udp" return',
                      'tcp dport {1720} ct helper set "q931_tcp" return']
     },
     'nfs': {
         'nftables': ['tcp dport {111} ct helper set "rpc_tcp" return',
                      'udp dport {111} ct helper set "rpc_udp" return']
     },
     'pptp': {
         'ko': ['nf_nat_pptp', 'nf_conntrack_pptp'],
         'nftables': ['tcp dport {1723} ct helper set "pptp_tcp" return'],
         'ipv4': True
      },
+    'rtsp': {
+        'ko': ['nf_nat_rtsp', 'nf_conntrack_rtsp'],
+        'nftables': ['tcp dport {554} ct helper set "rtsp_tcp" return'],
+        'ipv4': True
+    },
     'sip': {
         'ko': ['nf_nat_sip', 'nf_conntrack_sip'],
         'nftables': ['tcp dport {5060,5061} ct helper set "sip_tcp" return',
                      'udp dport {5060,5061} ct helper set "sip_udp" return']
      },
     'sqlnet': {
         'nftables': ['tcp dport {1521,1525,1536} ct helper set "tns_tcp" return']
     },
     'tftp': {
         'ko': ['nf_nat_tftp', 'nf_conntrack_tftp'],
         'nftables': ['udp dport {69} ct helper set "tftp_udp" return']
      },
 }
 
 valid_groups = [
     'address_group',
     'domain_group',
     'network_group',
     'port_group'
 ]
 
 def get_config(config=None):
     if config:
         conf = config
     else:
         conf = Config()
     base = ['system', 'conntrack']
 
     conntrack = conf.get_config_dict(base, key_mangling=('-', '_'),
                                      get_first_key=True,
                                      with_recursive_defaults=True)
 
     conntrack['firewall'] = conf.get_config_dict(['firewall'], key_mangling=('-', '_'),
                                                  get_first_key=True,
                                                  no_tag_node_value_mangle=True)
 
     conntrack['ipv4_nat_action'] = 'accept' if conf.exists(['nat']) else 'return'
     conntrack['ipv6_nat_action'] = 'accept' if conf.exists(['nat66']) else 'return'
     conntrack['wlb_action'] = 'accept' if conf.exists(['load-balancing', 'wan']) else 'return'
     conntrack['wlb_local_action'] = conf.exists(['load-balancing', 'wan', 'enable-local-traffic'])
 
     conntrack['module_map'] = module_map
 
     if conf.exists(['service', 'conntrack-sync']):
         set_dependents('conntrack_sync', conf)
 
     # If conntrack status changes, VRF zone rules need updating
     if conf.exists(['vrf']):
         set_dependents('vrf', conf)
 
     return conntrack
 
 def verify(conntrack):
     for inet in ['ipv4', 'ipv6']:
         if dict_search_args(conntrack, 'ignore', inet, 'rule') != None:
             for rule, rule_config in conntrack['ignore'][inet]['rule'].items():
                 if dict_search('destination.port', rule_config) or \
                    dict_search('destination.group.port_group', rule_config) or \
                    dict_search('source.port', rule_config) or \
                    dict_search('source.group.port_group', rule_config):
                    if 'protocol' not in rule_config or rule_config['protocol'] not in ['tcp', 'udp']:
                        raise ConfigError(f'Port requires tcp or udp as protocol in rule {rule}')
 
                 tcp_flags = dict_search_args(rule_config, 'tcp', 'flags')
                 if tcp_flags:
                     if dict_search_args(rule_config, 'protocol') != 'tcp':
                         raise ConfigError('Protocol must be tcp when specifying tcp flags')
 
                     not_flags = dict_search_args(rule_config, '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')
 
                 for side in ['destination', 'source']:
                     if side in rule_config:
                         side_conf = rule_config[side]
 
                         if 'group' in side_conf:
                             if len({'address_group', 'network_group', 'domain_group'} & set(side_conf['group'])) > 1:
                                 raise ConfigError('Only one address-group, network-group or domain-group can be specified')
 
                             for group in valid_groups:
                                 if group in side_conf['group']:
                                     group_name = side_conf['group'][group]
                                     error_group = group.replace("_", "-")
 
                                     if group in ['address_group', 'network_group', 'domain_group']:
                                         if 'address' in side_conf:
                                             raise ConfigError(f'{error_group} and address cannot both be defined')
 
                                     if group_name and group_name[0] == '!':
                                         group_name = group_name[1:]
 
                                     if inet == 'ipv6':
                                         group = f'ipv6_{group}'
 
                                     group_obj = dict_search_args(conntrack['firewall'], 'group', group, group_name)
 
                                     if group_obj is None:
                                         raise ConfigError(f'Invalid {error_group} "{group_name}" on ignore rule')
 
                                     if not group_obj:
                                         Warning(f'{error_group} "{group_name}" has no members!')
 
         if dict_search_args(conntrack, 'timeout', 'custom', inet, 'rule') != None:
             for rule, rule_config in conntrack['timeout']['custom'][inet]['rule'].items():
                 if 'protocol' not in rule_config:
                     raise ConfigError(f'Conntrack custom timeout rule {rule} requires protocol tcp or udp')
                 else:
                     if 'tcp' in rule_config['protocol'] and 'udp' in rule_config['protocol']:
                         raise ConfigError(f'conntrack custom timeout rule {rule} - Cant use both tcp and udp protocol')
     return None
 
 def generate(conntrack):
     if not os.path.exists(nftables_ct_file):
         conntrack['first_install'] = True
 
     # Determine if conntrack is needed
     conntrack['ipv4_firewall_action'] = 'return'
     conntrack['ipv6_firewall_action'] = 'return'
 
     for rules, path in dict_search_recursive(conntrack['firewall'], 'rule'):
         if any(('state' in rule_conf or 'connection_status' in rule_conf or 'offload_target' in rule_conf) for rule_conf in rules.values()):
             if path[0] == 'ipv4':
                 conntrack['ipv4_firewall_action'] = 'accept'
             elif path[0] == 'ipv6':
                 conntrack['ipv6_firewall_action'] = 'accept'
 
     render(conntrack_config, 'conntrack/vyos_nf_conntrack.conf.j2', conntrack)
     render(sysctl_file, 'conntrack/sysctl.conf.j2', conntrack)
     render(nftables_ct_file, 'conntrack/nftables-ct.j2', conntrack)
     return None
 
 def apply(conntrack):
     # Depending on the enable/disable state of the ALG (Application Layer Gateway)
     # modules we need to either insmod or rmmod the helpers.
-    
+
     add_modules = []
     rm_modules = []
 
     for module, module_config in module_map.items():
         if dict_search_args(conntrack, 'modules', module) is None:
             if 'ko' in module_config:
                 unloaded = [mod for mod in module_config['ko'] if os.path.exists(f'/sys/module/{mod}')]
                 rm_modules.extend(unloaded)
         else:
             if 'ko' in module_config:
                 add_modules.extend(module_config['ko'])
 
     # Add modules before nftables uses them
     if add_modules:
         module_str = ' '.join(add_modules)
         cmd(f'modprobe -a {module_str}')
 
     # Load new nftables ruleset
     install_result, output = rc_cmd(f'nft -f {nftables_ct_file}')
     if install_result == 1:
         raise ConfigError(f'Failed to apply configuration: {output}')
 
     # Remove modules after nftables stops using them
     if rm_modules:
         module_str = ' '.join(rm_modules)
         cmd(f'rmmod {module_str}')
 
     try:
         call_dependents()
     except ConfigError:
         # Ignore config errors on dependent due to being called too early. Example:
         # ConfigError("ConfigError('Interface ethN requires an IP address!')")
         pass
 
     # We silently ignore all errors
     # See: https://bugzilla.redhat.com/show_bug.cgi?id=1264080
     cmd(f'sysctl -f {sysctl_file}')
 
     return None
 
 if __name__ == '__main__':
     try:
         c = get_config()
         verify(c)
         generate(c)
         apply(c)
     except ConfigError as e:
         print(e)
         exit(1)