From 025438ccacc654274efbd3bea8b13fcc73ae08b6 Mon Sep 17 00:00:00 2001
From: l0crian1 <ryan.claridge13@gmail.com>
Date: Mon, 1 Apr 2024 11:14:54 -0400
Subject: 	modified:   op-mode-definitions/firewall.xml.in       - Added
 show firewall <sections> detail paths 	modified:   src/op_mode/firewall.py   
    - Added Description as a header to normal "show firewall" commands       -
 Added 'detail' view which shows the output in a list key-pair format
 Description column was added for these commands and their subsections: show
 firewall statistics show firewall groups show firewall <family>

Detail view was added for these commands:
show firewall bridge forward filter detail
show firewall bridge forward filter rule <rule#> detail
show firewall bridge name <chain> detail
show firewall bridge name <chain> rule <rule#> detail

show firewall ipv4 forward filter detail
show firewall ipv4 forward filter rule <rule#> detail
show firewall ipv4 input filter detail
show firewall ipv4 input filter rule <rule#> detail
show firewall ipv4 output filter detail
show firewall ipv4 output filter rule <rule#> detail
show firewall ipv4 name <chain> detail
show firewall ipv4 name <chain> rule <rule#> detail

show firewall ipv6 forward filter detail
show firewall ipv6 forward filter rule <rule#> detail
show firewall ipv6 input filter detail
show firewall ipv6 input filter rule <rule#> detail
show firewall ipv6 output filter detail
show firewall ipv6 output filter rule <rule#> detail
show firewall ipv6 name <chain> detail
show firewall ipv6 name <chain> rule <rule#> detail

show firewall group detail
show firewall group <group> detail
---
 op-mode-definitions/firewall.xml.in | 241 +++++++++++++++++++++++++++++++++++-
 src/op_mode/firewall.py             |  38 ++++--
 2 files changed, 267 insertions(+), 12 deletions(-)

diff --git a/op-mode-definitions/firewall.xml.in b/op-mode-definitions/firewall.xml.in
index 50d52d6ca..6a254ee11 100644
--- a/op-mode-definitions/firewall.xml.in
+++ b/op-mode-definitions/firewall.xml.in
@@ -19,14 +19,36 @@
                 <path>firewall group ipv6-network-group</path>
               </completionHelp>
             </properties>
+            <children>
+              <leafNode name="detail">
+                <properties>
+                  <help>Show list view of firewall groups</help>
+                  <completionHelp>
+                    <path>firewall group detail</path>
+                  </completionHelp>
+                </properties>
+                <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show_group --name $4 --detail $5</command>
+              </leafNode>
+            </children>
             <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show_group --name $4</command>
           </tagNode>
-          <leafNode name="group">
+          <node name="group">
             <properties>
               <help>Show firewall group</help>
             </properties>
+            <children>
+              <leafNode name="detail">
+                <properties>
+                  <help>Show list view of firewall group</help>
+                  <completionHelp>
+                    <path>firewall group detail</path>
+                  </completionHelp>
+                </properties>
+                <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show_group --detail $4</command>
+              </leafNode>
+            </children>
             <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show_group</command>
-          </leafNode>
+          </node>
           <node name="bridge">
             <properties>
               <help>Show bridge firewall</help>
@@ -42,6 +64,15 @@
                       <help>Show bridge forward filter firewall ruleset</help>
                     </properties>
                     <children>
+                      <leafNode name="detail">
+                        <properties>
+                          <help>Show list view of bridge forward filter firewall rules</help>
+                          <completionHelp>
+                            <path>firewall bridge forward filter detail</path>
+                          </completionHelp>
+                        </properties>
+                        <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --detail $6</command>
+                      </leafNode>
                       <tagNode name="rule">
                         <properties>
                           <help>Show summary of bridge forward filter firewall rules</help>
@@ -49,6 +80,17 @@
                             <path>firewall bridge forward filter rule</path>
                           </completionHelp>
                         </properties>
+                        <children>
+                          <leafNode name="detail">
+                            <properties>
+                              <help>Show list view of specific bridge forward filter firewall rule</help>
+                              <completionHelp>
+                                <path>firewall bridge forward filter detail</path>
+                              </completionHelp>
+                            </properties>
+                            <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7 --detail $8</command>
+                          </leafNode>
+                        </children>
                         <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7</command>
                       </tagNode>
                     </children>
@@ -64,6 +106,15 @@
                   </completionHelp>
                 </properties>
                 <children>
+                  <leafNode name="detail">
+                    <properties>
+                      <help>Show list view of bridge custom firewall chains</help>
+                      <completionHelp>
+                        <path>firewall bridge name detail</path>
+                      </completionHelp>
+                    </properties>
+                    <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --detail $6</command>
+                  </leafNode>
                   <tagNode name="rule">
                     <properties>
                       <help>Show summary of bridge custom firewall ruleset</help>
@@ -71,6 +122,17 @@
                         <path>firewall bridge name ${COMP_WORDS[5]} rule</path>
                       </completionHelp>
                     </properties>
+                    <children>
+                      <leafNode name="detail">
+                        <properties>
+                          <help>Show list view of bridge custom firewall rules</help>
+                          <completionHelp>
+                            <path>firewall bridge name ${COMP_WORDS[5]} rule detail</path>
+                          </completionHelp>
+                        </properties>
+                        <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7 --detail $8</command>
+                      </leafNode>
+                    </children>
                     <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7</command>
                   </tagNode>
                 </children>
@@ -94,6 +156,15 @@
                       <help>Show IPv6 forward filter firewall ruleset</help>
                     </properties>
                     <children>
+                      <leafNode name="detail">
+                        <properties>
+                          <help>Show list view of IPv6 forward filter firewall ruleset</help>
+                          <completionHelp>
+                            <path>firewall ipv6 forward filter detail</path>
+                          </completionHelp>
+                        </properties>
+                        <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --detail $6</command>
+                      </leafNode>
                       <tagNode name="rule">
                         <properties>
                           <help>Show summary of IPv6 forward filter firewall rules</help>
@@ -101,6 +172,17 @@
                             <path>firewall ipv6 forward filter rule</path>
                           </completionHelp>
                         </properties>
+                        <children>
+                          <leafNode name="detail">
+                            <properties>
+                              <help>Show list view of IPv6 forward filter firewall rules</help>
+                              <completionHelp>
+                                <path>firewall ipv6 forward filter rule detail</path>
+                              </completionHelp>
+                            </properties>
+                            <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7 --detail $8</command>
+                          </leafNode>
+                        </children>
                         <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7</command>
                       </tagNode>
                     </children>
@@ -118,6 +200,15 @@
                       <help>Show IPv6 forward input firewall ruleset</help>
                     </properties>
                     <children>
+                      <leafNode name="detail">
+                        <properties>
+                          <help>Show list view of IPv6 input firewall ruleset</help>
+                          <completionHelp>
+                            <path>firewall ipv6 input filter detail</path>
+                          </completionHelp>
+                        </properties>
+                        <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --detail $6</command>
+                      </leafNode>
                       <tagNode name="rule">
                         <properties>
                           <help>Show summary of IPv6 input filter firewall rules</help>
@@ -125,6 +216,17 @@
                             <path>firewall ipv6 input filter rule</path>
                           </completionHelp>
                         </properties>
+                        <children>
+                          <leafNode name="detail">
+                            <properties>
+                              <help>Show list view of IPv6 input filter firewall rules</help>
+                              <completionHelp>
+                                <path>firewall ipv6 input filter rule detail</path>
+                              </completionHelp>
+                            </properties>
+                            <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7 --detail $8</command>
+                          </leafNode>
+                        </children>
                         <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7</command>
                       </tagNode>
                     </children>
@@ -142,6 +244,15 @@
                       <help>Show IPv6 output filter firewall ruleset</help>
                     </properties>
                     <children>
+                      <leafNode name="detail">
+                        <properties>
+                          <help>Show list view of IPv6 output input firewall ruleset</help>
+                          <completionHelp>
+                            <path>firewall ipv6 output filter detail</path>
+                          </completionHelp>
+                        </properties>
+                        <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --detail $6</command>
+                      </leafNode>
                       <tagNode name="rule">
                         <properties>
                           <help>Show summary of IPv6 output filter firewall rules</help>
@@ -149,6 +260,17 @@
                             <path>firewall ipv6 output filter rule</path>
                           </completionHelp>
                         </properties>
+                        <children>
+                          <leafNode name="detail">
+                            <properties>
+                              <help>Show list view of IPv6 output filter firewall rules</help>
+                              <completionHelp>
+                                <path>firewall ipv6 output filter rule detail</path>
+                              </completionHelp>
+                            </properties>
+                            <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7 --detail $8</command>
+                          </leafNode>
+                        </children>
                         <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7</command>
                       </tagNode>
                     </children>
@@ -164,6 +286,15 @@
                   </completionHelp>
                 </properties>
                 <children>
+                  <leafNode name="detail">
+                    <properties>
+                      <help>Show list view of IPv6 custom firewall chains</help>
+                      <completionHelp>
+                        <path>firewall ipv6 name detail</path>
+                      </completionHelp>
+                    </properties>
+                    <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --detail $6</command>
+                  </leafNode>
                   <tagNode name="rule">
                     <properties>
                       <help>Show summary of IPv6 custom firewall ruleset</help>
@@ -171,6 +302,17 @@
                         <path>firewall ipv6 name ${COMP_WORDS[5]} rule</path>
                       </completionHelp>
                     </properties>
+                    <children>
+                      <leafNode name="detail">
+                        <properties>
+                          <help>Show list view of IPv6 custom firewall rules</help>
+                          <completionHelp>
+                            <path>firewall ipv6 name ${COMP_WORDS[5]} rule detail</path>
+                          </completionHelp>
+                        </properties>
+                        <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7 --detail $8</command>
+                      </leafNode>
+                    </children>
                     <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7</command>
                   </tagNode>
                 </children>
@@ -194,6 +336,15 @@
                       <help>Show IPv4 forward filter firewall ruleset</help>
                     </properties>
                     <children>
+                      <leafNode name="detail">
+                        <properties>
+                          <help>Show list view of IPv4 forward filter firewall ruleset</help>
+                          <completionHelp>
+                            <path>firewall ipv4 forward filter detail</path>
+                          </completionHelp>
+                        </properties>
+                        <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --detail $6</command>
+                      </leafNode>
                       <tagNode name="rule">
                         <properties>
                           <help>Show summary of IPv4 forward filter firewall rules</help>
@@ -201,6 +352,17 @@
                             <path>firewall ipv4 forward filter rule</path>
                           </completionHelp>
                         </properties>
+                        <children>
+                          <leafNode name="detail">
+                            <properties>
+                              <help>Show list view of IPv4 forward filter firewall rules</help>
+                              <completionHelp>
+                                <path>firewall ipv4 forward filter rule detail</path>
+                              </completionHelp>
+                            </properties>
+                            <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7 --detail $8</command>
+                          </leafNode>
+                        </children>
                         <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7</command>
                       </tagNode>
                     </children>
@@ -218,6 +380,15 @@
                       <help>Show IPv4 forward input firewall ruleset</help>
                     </properties>
                     <children>
+                      <leafNode name="detail">
+                        <properties>
+                          <help>Show list view of IPv4 input filter firewall ruleset</help>
+                          <completionHelp>
+                            <path>firewall ipv4 input filter detail</path>
+                          </completionHelp>
+                        </properties>
+                        <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --detail $6</command>
+                      </leafNode>
                       <tagNode name="rule">
                         <properties>
                           <help>Show summary of IPv4 input filter firewall rules</help>
@@ -225,6 +396,17 @@
                             <path>firewall ipv4 input filter rule</path>
                           </completionHelp>
                         </properties>
+                        <children>
+                          <leafNode name="detail">
+                            <properties>
+                              <help>Show list view of IPv4 input filter firewall rules</help>
+                              <completionHelp>
+                                <path>firewall ipv4 input filter rule detail</path>
+                              </completionHelp>
+                            </properties>
+                            <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7 --detail $8</command>
+                          </leafNode>
+                        </children>
                         <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7</command>
                       </tagNode>
                     </children>
@@ -242,6 +424,15 @@
                       <help>Show IPv4 output filter firewall ruleset</help>
                     </properties>
                     <children>
+                      <leafNode name="detail">
+                        <properties>
+                          <help>Show list view of IPv4 output filter firewall ruleset</help>
+                          <completionHelp>
+                            <path>firewall ipv4 input output detail</path>
+                          </completionHelp>
+                        </properties>
+                        <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --detail $6</command>
+                      </leafNode>
                       <tagNode name="rule">
                         <properties>
                           <help>Show summary of IPv4 output filter firewall rules</help>
@@ -249,6 +440,17 @@
                             <path>firewall ipv4 output filter rule</path>
                           </completionHelp>
                         </properties>
+                        <children>
+                          <leafNode name="detail">
+                            <properties>
+                              <help>Show list view of IPv4 output filter firewall rules</help>
+                              <completionHelp>
+                                <path>firewall ipv4 input output rule detail</path>
+                              </completionHelp>
+                            </properties>
+                            <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7 --detail $8</command>
+                          </leafNode>
+                        </children>
                         <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7</command>
                       </tagNode>
                     </children>
@@ -264,6 +466,15 @@
                   </completionHelp>
                 </properties>
                 <children>
+                  <leafNode name="detail">
+                    <properties>
+                      <help>Show list view of IPv4 custom firewall chains</help>
+                      <completionHelp>
+                        <path>firewall ipv4 name detail</path>
+                      </completionHelp>
+                    </properties>
+                    <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --detail $6</command>
+                  </leafNode>
                   <tagNode name="rule">
                     <properties>
                       <help>Show summary of IPv4 custom firewall ruleset</help>
@@ -271,6 +482,17 @@
                         <path>firewall ipv4 name ${COMP_WORDS[5]} rule</path>
                       </completionHelp>
                     </properties>
+                    <children>
+                      <leafNode name="detail">
+                        <properties>
+                          <help>Show list view of IPv4 custom firewall ruleset</help>
+                          <completionHelp>
+                            <path>firewall ipv4 name ${COMP_WORDS[5]} rule detail</path>
+                          </completionHelp>
+                        </properties>
+                        <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7 --detail $8</command>
+                      </leafNode>
+                    </children>
                     <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show --family $3 --hook $4 --priority $5 --rule $7</command>
                   </tagNode>
                 </children>
@@ -279,12 +501,23 @@
             </children>
           <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show_family --family $3</command>
           </node>
-          <leafNode name="statistics">
+          <node name="statistics">
             <properties>
               <help>Show statistics of firewall application</help>
             </properties>
+            <children>
+              <leafNode name="detail">
+                <properties>
+                  <help>Show list view of firewall statistics</help>
+                  <completionHelp>
+                    <path>firewall statistics detail</path>
+                  </completionHelp>
+                </properties>
+                <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show_statistics --detail $4</command>
+              </leafNode>
+            </children>
             <command>sudo ${vyos_op_scripts_dir}/firewall.py --action show_statistics</command>
-          </leafNode>
+          </node>
           <leafNode name="summary">
             <properties>
               <help>Show summary of firewall application</help>
diff --git a/src/op_mode/firewall.py b/src/op_mode/firewall.py
index 7134187fe..411e0be20 100755
--- a/src/op_mode/firewall.py
+++ b/src/op_mode/firewall.py
@@ -19,6 +19,7 @@ import ipaddress
 import json
 import re
 import tabulate
+import textwrap
 
 from vyos.config import Config
 from vyos.utils.process import cmd
@@ -89,6 +90,17 @@ def get_nftables_details(family, hook, priority):
         out[rule_id] = rule
     return out
 
+def output_firewall_vertical(rules, headers):
+    if args.rule:
+        rules.pop()
+
+    for rule in rules:
+        adjusted_rule = rule + [""] * (len(headers) - len(rule)) # account for different header length, like default-action
+        transformed_rule = [[header, textwrap.fill(adjusted_rule[i].replace('\n', ' '), 100)] for i, header in enumerate(headers)] # create key-pair list from headers and rules lists; wrap at 100 char
+
+        print(tabulate.tabulate(transformed_rule, tablefmt="presto"))
+        print()
+
 def output_firewall_name(family, hook, priority, firewall_conf, single_rule_id=None):
     print(f'\n---------------------------------\n{family} Firewall "{hook} {priority}"\n')
 
@@ -103,7 +115,7 @@ def output_firewall_name(family, hook, priority, firewall_conf, single_rule_id=N
             if 'disable' in rule_conf:
                 continue
 
-            row = [rule_id, rule_conf.get('description', ''), rule_conf['action'], rule_conf['protocol'] if 'protocol' in rule_conf else 'all']
+            row = [rule_id, textwrap.fill(rule_conf.get('description') or '', 50), rule_conf['action'], rule_conf['protocol'] if 'protocol' in rule_conf else 'all']
             if rule_id in details:
                 rule_details = details[rule_id]
                 row.append(rule_details.get('packets', 0))
@@ -124,7 +136,10 @@ def output_firewall_name(family, hook, priority, firewall_conf, single_rule_id=N
 
     if rows:
         header = ['Rule', 'Description', 'Action', 'Protocol', 'Packets', 'Bytes', 'Conditions']
-        print(tabulate.tabulate(rows, header) + '\n')
+        if args.detail:
+            output_firewall_vertical(rows, header)
+        else:
+            print(tabulate.tabulate(rows, header) + '\n')
 
 def output_firewall_name_statistics(family, hook, prior, prior_conf, single_rule_id=None):
     print(f'\n---------------------------------\n{family} Firewall "{hook} {prior}"\n')
@@ -192,7 +207,7 @@ def output_firewall_name_statistics(family, hook, prior, prior_conf, single_rule
                 if not oiface:
                     oiface = 'any'
 
-            row = [rule_id, rule_conf.get('description', '')]
+            row = [rule_id, textwrap.fill(rule_conf.get('description') or '', 50)]
             if rule_id in details:
                 rule_details = details[rule_id]
                 row.append(rule_details.get('packets', 0))
@@ -241,7 +256,10 @@ def output_firewall_name_statistics(family, hook, prior, prior_conf, single_rule
 
     if rows:
         header = ['Rule', 'Description', 'Packets', 'Bytes', 'Action', 'Source', 'Destination', 'Inbound-Interface', 'Outbound-interface']
-        print(tabulate.tabulate(rows, header) + '\n')
+        if args.detail:
+            output_firewall_vertical(rows, header)
+        else:
+            print(tabulate.tabulate(rows, header) + '\n')
 
 def show_firewall():
     print('Rulesets Information')
@@ -429,7 +447,7 @@ def show_firewall_group(name=None):
 
         return out
 
-    header = ['Name', 'Type', 'References', 'Members']
+    header = ['Name', 'Description','Type', 'References', 'Members']
     rows = []
 
     for group_type, group_type_conf in firewall['group'].items():
@@ -441,7 +459,7 @@ def show_firewall_group(name=None):
                     continue
 
                 references = find_references(group_type, group_name)
-                row = [group_name, group_type, '\n'.join(references) or 'N/D']
+                row = [group_name,  textwrap.fill(group_conf.get('description') or '', 50), group_type, '\n'.join(references) or 'N/D']
                 if 'address' in group_conf:
                     row.append("\n".join(sorted(group_conf['address'])))
                 elif 'network' in group_conf:
@@ -461,13 +479,16 @@ def show_firewall_group(name=None):
                 if dynamic_type in firewall['group']['dynamic_group']:
                     for dynamic_name, dynamic_conf in firewall['group']['dynamic_group'][dynamic_type].items():
                         references = find_references(dynamic_type, dynamic_name)
-                        row = [dynamic_name, dynamic_type + '(dynamic)', '\n'.join(references) or 'N/D']
+                        row = [dynamic_name, textwrap.fill(dynamic_conf.get('description') or '', 50), dynamic_type + '(dynamic)', '\n'.join(references) or 'N/D']
                         row.append('N/D')
                         rows.append(row)
 
     if rows:
         print('Firewall Groups\n')
-        print(tabulate.tabulate(rows, header))
+        if args.detail:
+            output_firewall_vertical(rows, header)
+        else:
+            print(tabulate.tabulate(rows, header))
 
 def show_summary():
     print('Ruleset Summary')
@@ -539,6 +560,7 @@ if __name__ == '__main__':
     parser.add_argument('--priority', help='Firewall priority', required=False, action='store', nargs='?', default='')
     parser.add_argument('--rule', help='Firewall Rule ID', required=False)
     parser.add_argument('--ipv6', help='IPv6 toggle', action='store_true')
+    parser.add_argument('--detail', help='Firewall view select', required=False)
 
     args = parser.parse_args()
 
-- 
cgit v1.2.3