From 9fd08c928a2b6a3c5a82edf6835452a906887110 Mon Sep 17 00:00:00 2001
From: Jonathan <jonathan.leon@pandorafms.com>
Date: Mon, 19 Jun 2023 16:14:21 +0200
Subject: [PATCH] #11573 network filters

---
 pandora_console/extras/mr/65.sql              |  21 +
 pandora_console/include/functions_netflow.php |  18 +-
 .../operation/network/network_report.php      | 359 +++++++++++++-----
 .../operation/network/network_usage_map.php   | 140 ++++++-
 pandora_console/pandoradb.sql                 |  24 ++
 5 files changed, 453 insertions(+), 109 deletions(-)
 create mode 100644 pandora_console/extras/mr/65.sql

diff --git a/pandora_console/extras/mr/65.sql b/pandora_console/extras/mr/65.sql
new file mode 100644
index 0000000000..7f7a423fcf
--- /dev/null
+++ b/pandora_console/extras/mr/65.sql
@@ -0,0 +1,21 @@
+START TRANSACTION;
+
+CREATE TABLE IF NOT EXISTS `tnetwork_explorer_filter` (
+`id` INT NOT NULL,
+`filter_name` VARCHAR(45) NULL,
+`top` VARCHAR(45) NULL,
+`action` VARCHAR(45) NULL,
+`advanced_filter` TEXT NULL,
+PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
+
+CREATE TABLE IF NOT EXISTS `tnetwork_usage_filter` (
+`id` INT NOT NULL auto_increment,
+`filter_name` VARCHAR(45) NULL,
+`top` VARCHAR(45) NULL,
+`action` VARCHAR(45) NULL,
+`advanced_filter` TEXT NULL,
+PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
+
+COMMIT;
diff --git a/pandora_console/include/functions_netflow.php b/pandora_console/include/functions_netflow.php
index 66e1ad1a9f..7d7000ae5b 100644
--- a/pandora_console/include/functions_netflow.php
+++ b/pandora_console/include/functions_netflow.php
@@ -1734,7 +1734,12 @@ function netflow_get_top_summary(
     switch ($top_action) {
         case 'listeners':
             if (empty(!$filter)) {
-                $netflow_filter['ip_src'] = $filter;
+                if (!is_array($filter)) {
+                    $netflow_filter['ip_src'] = $filter;
+                } else {
+                    $netflow_filter['ip_src'] = $filter['ip'];
+                    $netflow_filter['advanced_filter'] = $filter['advanced_filter'];
+                }
             }
 
             $sort = 'dstip';
@@ -1742,7 +1747,12 @@ function netflow_get_top_summary(
 
         case 'talkers':
             if (empty(!$filter)) {
-                $netflow_filter['ip_dst'] = $filter;
+                if (!is_array($filter)) {
+                    $netflow_filter['ip_dst'] = $filter;
+                } else {
+                    $netflow_filter['ip_dst'] = $filter['ip'];
+                    $netflow_filter['advanced_filter'] = $filter['advanced_filter'];
+                }
             }
 
             $sort = 'srcip';
@@ -2069,7 +2079,7 @@ function netflow_aggregate_is_ip($aggregate)
  *
  * @return array With map structure.
  */
-function netflow_build_map_data($start_date, $end_date, $top, $aggregate)
+function netflow_build_map_data($start_date, $end_date, $top, $aggregate, $advanced_filter='')
 {
     // Pass an empty filter data structure.
     $data = netflow_get_relationships_raw_data(
@@ -2083,7 +2093,7 @@ function netflow_build_map_data($start_date, $end_date, $top, $aggregate)
             'ip_src'          => '',
             'dst_port'        => '',
             'src_port'        => '',
-            'advanced_filter' => '',
+            'advanced_filter' => $advanced_filter,
             'router_ip'       => '',
         ],
         $top,
diff --git a/pandora_console/operation/network/network_report.php b/pandora_console/operation/network/network_report.php
index 5d036df61a..c4e9a01365 100644
--- a/pandora_console/operation/network/network_report.php
+++ b/pandora_console/operation/network/network_report.php
@@ -39,10 +39,26 @@ if (! check_acl($config['id_user'], 0, 'AR')) {
     exit;
 }
 
+// Ajax callbacks.
+if (is_ajax() === true) {
+    $get_filter_values = get_parameter('get_filter_values', 0);
+    // Get values of the current network filter.
+    if ($get_filter_values) {
+        $id = get_parameter('id');
+        $filter_values = db_get_row_filter('tnetwork_explorer_filter', ['id' => $id]);
+        // Decode HTML entities.
+        $filter_values['advanced_filter'] = io_safe_output($filter_values['advanced_filter']);
+        echo json_encode($filter_values);
+    }
+
+    return;
+}
+
 // Include JS timepicker.
 ui_include_time_picker();
 
 // Query params and other initializations.
+$filter_id = (int) get_parameter('filter_id', 0);
 $time_greater = get_parameter('time_greater', date(TIME_FORMAT));
 $date_greater = get_parameter('date_greater', date(DATE_FORMAT));
 $utimestamp_greater = strtotime($date_greater.' '.$time_greater);
@@ -59,6 +75,13 @@ $top = (int) get_parameter('top', 10);
 $main_value = ((bool) get_parameter('remove_filter', 0)) ? '' : get_parameter('main_value', '');
 if (is_numeric($main_value) && !in_array($action, ['udp', 'tcp'])) {
     $main_value = '';
+} else {
+    $filter['ip'] = $main_value;
+}
+
+$advanced_filter = get_parameter('advanced_filter', '');
+if ($advanced_filter !== '') {
+    $filter['advanced_filter'] = $advanced_filter;
 }
 
 $order_by = get_parameter('order_by', 'bytes');
@@ -66,30 +89,143 @@ if (!in_array($order_by, ['bytes', 'pkts', 'flows'])) {
     $order_by = 'bytes';
 }
 
-$style_end = ($is_period) ? 'display: none;' : '';
-$style_period = ($is_period) ? '' : 'display: none;';
+$save = get_parameter('save_button', '');
+$update = get_parameter('update_button', '');
+
+// Save user defined filter.
+if ($save != '' && check_acl($config['id_user'], 0, 'AW')) {
+    // Save filter args.
+    $data['filter_name'] = get_parameter('filter_name');
+    $data['top'] = $top;
+    $data['action'] = $action;
+    $data['advanced_filter'] = $advanced_filter;
+
+
+    $filter_id = db_process_sql_insert('tnetwork_explorer_filter', $data);
+    if ($filter_id === false) {
+        $filter_id = 0;
+        ui_print_error_message(__('Error creating filter'));
+    } else {
+        ui_print_success_message(__('Filter created successfully'));
+    }
+} else if ($update != '' && check_acl($config['id_user'], 0, 'AW')) {
+    // Update current filter.
+    // Do not update the filter name and group.
+    $data['top'] = $top;
+    $data['action'] = $action;
+    $data['advanced_filter'] = $advanced_filter;
+
+    $result = db_process_sql_update(
+        'tnetwork_explorer_filter',
+        $data,
+        ['id' => $filter_id]
+    );
+    ui_print_result_message(
+        $result,
+        __('Filter updated successfully'),
+        __('Error updating filter')
+    );
+}
 
 // Build the table.
-$table = new stdClass();
-$table->class = 'filter-table-adv';
-$table->width = '100%';
-$table->data = [];
+$filterTable = new stdClass();
+$filterTable->id = '';
+$filterTable->class = 'filter-table-adv';
+$filterTable->size = [];
+$filterTable->size[0] = '33%';
+$filterTable->size[1] = '33%';
+$filterTable->size[2] = '33%';
+$filterTable->data = [];
 
-$table->data[0][] = html_print_label_input_block(
-    __('Data to show'),
-    html_print_select(
-        network_get_report_actions(false),
-        'action',
-        $action,
+$filterTable->data[0][0] = html_print_label_input_block(
+    __('Interval'),
+    html_print_extended_select_for_time(
+        'period',
+        $period,
         '',
         '',
         0,
+        false,
+        true
+    ),
+    [ 'div_id' => 'period_container' ]
+);
+
+$filterTable->data[0][0] .= html_print_label_input_block(
+    __('Start date'),
+    html_print_div(
+        [
+            'class'   => '',
+            'content' => html_print_input_text(
+                'date_lower',
+                $date_lower,
+                false,
+                13,
+                10,
+                true
+            ).html_print_image(
+                'images/calendar_view_day.png',
+                true,
+                [
+                    'alt'   => 'calendar',
+                    'class' => 'main_menu_icon invert_filter',
+                ]
+            ).html_print_input_text(
+                'time_lower',
+                $time_lower,
+                false,
+                10,
+                8,
+                true
+            ),
+        ],
+        true
+    ),
+    [ 'div_id' => 'end_date_container' ]
+);
+
+$filterTable->data[0][1] = html_print_label_input_block(
+    __('End date'),
+    html_print_div(
+        [
+            'content' => html_print_input_text(
+                'date',
+                $date_greater,
+                false,
+                13,
+                10,
+                true
+            ).html_print_image(
+                'images/calendar_view_day.png',
+                true,
+                ['alt' => 'calendar']
+            ).html_print_input_text(
+                'time',
+                $time_greater,
+                false,
+                10,
+                8,
+                true
+            ),
+        ],
         true
     )
 );
 
-$table->data[0][] = html_print_label_input_block(
-    __('Number of result to show'),
+$filterTable->data[0][2] = html_print_label_input_block(
+    __('Defined period'),
+    html_print_checkbox_switch(
+        'is_period',
+        1,
+        ($is_period === true) ? 1 : 0,
+        true,
+        false,
+        'nf_view_click_period()'
+    )
+);
+
+$filterTable->data[1][] = html_print_label_input_block(
+    __('Results to show'),
     html_print_select(
         [
             '5'   => 5,
@@ -110,95 +246,62 @@ $table->data[0][] = html_print_label_input_block(
     )
 );
 
-$table->data[1][] = html_print_label_input_block(
-    __('Start date'),
-    html_print_div(
-        [
-            'id'      => 'end_date_container',
-            'content' => html_print_input_text(
-                'date_lower',
-                $date_lower,
-                '',
-                10,
-                10,
-                true
-            ).html_print_input_text(
-                'time_lower',
-                $time_lower,
-                '',
-                7,
-                8,
-                true
-            ),
-        ],
-        true
-    ).html_print_div(
-        [
-            'id'      => 'period_container',
-            'style'   => 'display: none;',
-            'content' => html_print_label_input_block(
-                '',
-                html_print_extended_select_for_time(
-                    'period',
-                    $period,
-                    '',
-                    '',
-                    0,
-                    false,
-                    true
-                ),
-            ),
-        ],
+$filterTable->data[1][] = html_print_label_input_block(
+    __('Data to show'),
+    html_print_select(
+        network_get_report_actions(),
+        'action',
+        $action,
+        '',
+        '',
+        0,
         true
     )
 );
 
-$table->data[1][] = html_print_label_input_block(
-    __('End date'),
-    html_print_div(
-        [
-            'id'      => '',
-            'class'   => '',
-            'content' => html_print_input_text(
-                'date_greater',
-                $date_greater,
-                '',
-                10,
-                10,
-                true
-            ).html_print_input_text(
-                'time_greater',
-                $time_greater,
-                '',
-                7,
-                8,
-                true
-            ),
-        ],
-        true
-    )
+$advanced_toggle = new stdClass();
+$advanced_toggle->class = 'filter-table-adv';
+$advanced_toggle->size = [];
+$advanced_toggle->size[0] = '50%';
+$advanced_toggle->size[1] = '50%';
+$advanced_toggle->width = '100%';
+$user_groups = users_get_groups($config['id_user'], 'AR', $own_info['is_admin'], true);
+$user_groups[0] = 0;
+// Add all groups.
+$sql = 'SELECT * FROM tnetwork_explorer_filter';
+$advanced_toggle->data[0][0] = html_print_label_input_block(
+    __('Load Filter'),
+    html_print_select_from_sql($sql, 'filter_id', $filter_id, '', __('Select a filter'), 0, true, false, true, false, 'width:100%;')
 );
-
-$table->data[2][] = html_print_label_input_block(
-    __('Defined period'),
-    html_print_checkbox_switch(
-        'is_period',
-        1,
-        ($is_period === true) ? 1 : 0,
+$advanced_toggle->data[0][1] = html_print_label_input_block(
+    __('Filter name'),
+    html_print_input_text('filter_name', '', false, 40, 45, true, false, false, '', 'w100p')
+);
+$advanced_toggle->colspan[1][0] = 2;
+$advanced_toggle->data[1][0] = html_print_label_input_block(
+    __('Filter').ui_print_help_icon('pcap_filter', true),
+    html_print_textarea('advanced_filter', 4, 10, $advanced_filter, 'style="width:100%"', true)
+);
+$filterTable->colspan[2][0] = 3;
+$filterTable->data[2][0] = html_print_label_input_block(
+    '',
+    ui_toggle(
+        html_print_table($advanced_toggle, true),
+        __('Advanced'),
+        '',
+        '',
         true,
-        false,
-        'network_report_click_period(event)'
+        true,
+        '',
+        'white-box-content',
+        'box-flat white_table_graph'
     )
 );
 
-echo '<form method="post">';
-html_print_input_hidden('order_by', $order_by);
-if (empty($main_value) === false) {
-    html_print_input_hidden('main_value', $main_value);
-}
-
-$outputTable = html_print_table($table, true);
-$outputTable .= html_print_div(
+$filterInputTable = '<form method="POST">';
+$filterInputTable .= html_print_input_hidden('order_by', $order_by);
+$filterInputTable .= html_print_table($filterTable, true);
+$filterInputTable .= html_print_div(
     [
         'class'   => 'action-buttons-right-forced',
         'content' => html_print_submit_button(
@@ -210,19 +313,48 @@ $outputTable .= html_print_div(
                 'mode' => 'mini',
             ],
             true
+        ).html_print_submit_button(
+            __('Save as new filter'),
+            'save_button',
+            false,
+            [
+                'icon'    => 'load',
+                'onClick' => 'return defineFilterName();',
+                'mode'    => 'mini secondary',
+                'class'   => 'mrgn_right_10px',
+            ],
+            true
+        ).html_print_submit_button(
+            __('Update current filter'),
+            'update_button',
+            false,
+            [
+                'icon'  => 'load',
+                'mode'  => 'mini secondary',
+                'class' => 'mrgn_right_10px',
+            ],
+            true
         ),
     ],
     true
 );
+$filterInputTable .= html_print_div(
+    [
+        'class'   => 'action-buttons',
+        'content' => $netflow_button,
+    ],
+    true
+);
+$filterInputTable .= '</form>';
 ui_toggle(
-    $outputTable,
-    '<span class="subsection_header_title">'.__('Filters').'</span>',
-    __('Filters'),
-    '',
+    $filterInputTable,
+    '<span class="subsection_header_title">'.__('Filter').'</span>',
+    __('Filter'),
+    'search',
     true,
     false,
     '',
-    'white-box-content',
+    'white-box-content no_border',
     'box-flat white_table_graph fixed_filter_bar'
 );
 html_print_action_buttons(
@@ -246,7 +378,7 @@ $data = netflow_get_top_summary(
     $action,
     $utimestamp_lower,
     $utimestamp_greater,
-    $main_value,
+    $filter,
     $order_by
 );
 
@@ -450,6 +582,26 @@ if (empty($data)) {
 
 ?>
 <script>
+$(document).ready(function(){
+    nf_view_click_period();
+
+    $('#filter_id').change(function(){
+        jQuery.post (
+        "ajax.php",
+        {
+            "page" : "operation/network/network_report",
+            "get_filter_values" : 1,
+            "id": $(this).val(),
+        },
+        function (data) {
+            $('#action').val(data.action).trigger('change');
+            $('#top').val(data.top).trigger('change');
+            $('#textarea_advanced_filter').val(data.advanced_filter);
+            $('select#filter_id').select2('close');
+        }, 'json');
+    });
+});
+
 // Configure jQuery timepickers.
 $("#text-time_lower, #text-time_greater").timepicker({
     showSecond: true,
@@ -472,4 +624,11 @@ function network_report_click_period(event) {
     document.getElementById('period_container').style.display = !is_period ? 'none' : 'block';
     document.getElementById('end_date_container').style.display = is_period ? 'none' : 'block';
 }
+
+function nf_view_click_period() {
+    var is_period = document.getElementById('checkbox-is_period').checked;
+
+    document.getElementById('period_container').style.display = !is_period ? 'none' : 'flex';
+    document.getElementById('end_date_container').style.display = is_period ? 'none' : 'flex';
+}
 </script>
diff --git a/pandora_console/operation/network/network_usage_map.php b/pandora_console/operation/network/network_usage_map.php
index 7e3964b277..76a5c396ad 100644
--- a/pandora_console/operation/network/network_usage_map.php
+++ b/pandora_console/operation/network/network_usage_map.php
@@ -34,6 +34,21 @@ global $config;
 
 check_login();
 
+// Ajax callbacks.
+if (is_ajax() === true) {
+    $get_filter_values = get_parameter('get_filter_values', 0);
+    // Get values of the current network filter.
+    if ($get_filter_values) {
+        $id = get_parameter('id');
+        $filter_values = db_get_row_filter('tnetwork_usage_filter', ['id' => $id]);
+        // Decode HTML entities.
+        $filter_values['advanced_filter'] = io_safe_output($filter_values['advanced_filter']);
+        echo json_encode($filter_values);
+    }
+
+    return;
+}
+
 // Header.
 ui_print_standard_header(
     __('Network usage map'),
@@ -76,6 +91,7 @@ $is_period = (bool) get_parameter('is_period', false);
 $period = (int) get_parameter('period', SECONDS_1HOUR);
 $time_lower = get_parameter('time_lower', date(TIME_FORMAT, ($utimestamp_greater - $period)));
 $date_lower = get_parameter('date_lower', date(DATE_FORMAT, ($utimestamp_greater - $period)));
+$advanced_filter = get_parameter('advanced_filter', '');
 $utimestamp_lower = ($is_period) ? ($utimestamp_greater - $period) : strtotime($date_lower.' '.$time_lower);
 if (!$is_period) {
     $period = ($utimestamp_greater - $utimestamp_lower);
@@ -88,6 +104,44 @@ if (in_array($order_by, ['bytes', 'pkts', 'flows']) === false) {
     $order_by = 'bytes';
 }
 
+$save = get_parameter('save_button', '');
+$update = get_parameter('update_button', '');
+
+// Save user defined filter.
+if ($save != '' && check_acl($config['id_user'], 0, 'AW')) {
+    // Save filter args.
+    $data['filter_name'] = get_parameter('filter_name');
+    $data['top'] = $top;
+    $data['action'] = $action;
+    $data['advanced_filter'] = $advanced_filter;
+
+
+    $filter_id = db_process_sql_insert('tnetwork_usage_filter', $data);
+    if ($filter_id === false) {
+        $filter_id = 0;
+        ui_print_error_message(__('Error creating filter'));
+    } else {
+        ui_print_success_message(__('Filter created successfully'));
+    }
+} else if ($update != '' && check_acl($config['id_user'], 0, 'AW')) {
+    // Update current filter.
+    // Do not update the filter name and group.
+    $data['top'] = $top;
+    $data['action'] = $action;
+    $data['advanced_filter'] = $advanced_filter;
+
+    $result = db_process_sql_update(
+        'tnetwork_usage_filter',
+        $data,
+        ['id' => $filter_id]
+    );
+    ui_print_result_message(
+        $result,
+        __('Filter updated successfully'),
+        __('Error updating filter')
+    );
+}
+
 if ((bool) $config['activate_netflow'] === true) {
     $netflow_button = html_print_submit_button(
         __('Show netflow map'),
@@ -95,6 +149,27 @@ if ((bool) $config['activate_netflow'] === true) {
         false,
         ['icon' => 'update'],
         true
+    ).html_print_submit_button(
+        __('Save as new filter'),
+        'save_button',
+        false,
+        [
+            'icon'    => 'load',
+            'onClick' => 'return defineFilterName();',
+            'mode'    => 'mini secondary',
+            'class'   => 'mrgn_right_10px',
+        ],
+        true
+    ).html_print_submit_button(
+        __('Update current filter'),
+        'update_button',
+        false,
+        [
+            'icon'  => 'load',
+            'mode'  => 'mini secondary',
+            'class' => 'mrgn_right_10px',
+        ],
+        true
     );
 } else {
     $netflow_button = '';
@@ -232,6 +307,44 @@ $filterTable->data[1][] = html_print_label_input_block(
     )
 );
 
+$advanced_toggle = new stdClass();
+$advanced_toggle->class = 'filter-table-adv';
+$advanced_toggle->size = [];
+$advanced_toggle->size[0] = '50%';
+$advanced_toggle->size[1] = '50%';
+$advanced_toggle->width = '100%';
+$user_groups = users_get_groups($config['id_user'], 'AR', $own_info['is_admin'], true);
+$user_groups[0] = 0;
+$sql = 'SELECT * FROM tnetwork_usage_filter';
+$advanced_toggle->data[0][0] = html_print_label_input_block(
+    __('Load Filter'),
+    html_print_select_from_sql($sql, 'filter_id', $filter_id, '', __('Select a filter'), 0, true, false, true, false, 'width:100%;')
+);
+$advanced_toggle->data[0][1] = html_print_label_input_block(
+    __('Filter name'),
+    html_print_input_text('filter_name', '', false, 40, 45, true, false, false, '', 'w100p')
+);
+$advanced_toggle->colspan[1][0] = 2;
+$advanced_toggle->data[1][0] = html_print_label_input_block(
+    __('Filter').ui_print_help_icon('pcap_filter', true),
+    html_print_textarea('advanced_filter', 4, 10, $advanced_filter, 'style="width:100%"', true)
+);
+$filterTable->colspan[2][0] = 3;
+$filterTable->data[2][0] = html_print_label_input_block(
+    '',
+    ui_toggle(
+        html_print_table($advanced_toggle, true),
+        __('Advanced'),
+        '',
+        '',
+        true,
+        true,
+        '',
+        'white-box-content',
+        'box-flat white_table_graph'
+    )
+);
+
 $filterInputTable = '<form method="POST">';
 $filterInputTable .= html_print_input_hidden('order_by', $order_by);
 $filterInputTable .= html_print_table($filterTable, true);
@@ -263,7 +376,8 @@ if ((bool) get_parameter('update_netflow') === true) {
         $utimestamp_lower,
         $utimestamp_greater,
         $top,
-        ($action === 'talkers') ? 'srcip' : 'dstip'
+        ($action === 'talkers') ? 'srcip' : 'dstip',
+        $advanced_filter
     );
     $has_data = !empty($map_data['nodes']);
 }
@@ -283,10 +397,26 @@ if ($has_data === true) {
 </style>
 <script>
 
-    $(document).ready(function(){
-        nf_view_click_period();
-    }
-    );
+$(document).ready(function(){
+    nf_view_click_period();
+
+    $('#filter_id').change(function(){
+        jQuery.post (
+        "ajax.php",
+        {
+            "page" : "operation/network/network_usage_map",
+            "get_filter_values" : 1,
+            "id": $(this).val(),
+        },
+        function (data) {
+            $('#action').val(data.action).trigger('change');
+            $('#top').val(data.top).trigger('change');
+            $('#textarea_advanced_filter').val(data.advanced_filter);
+            $('select#filter_id').select2('close');
+        }, 'json');
+    });
+});
+
 // Configure jQuery timepickers.
 $("#text-time_lower, #text-time_greater").timepicker({
     showSecond: true,
diff --git a/pandora_console/pandoradb.sql b/pandora_console/pandoradb.sql
index 8706e37fed..c802e4f4bf 100644
--- a/pandora_console/pandoradb.sql
+++ b/pandora_console/pandoradb.sql
@@ -4323,3 +4323,27 @@ CREATE TABLE IF NOT EXISTS `tsesion_filter_log_viewer` (
   `graph_type` INT NULL,
   PRIMARY KEY (`id_filter`)
 ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
+
+-- ---------------------------------------------------------------------
+-- Table `tnetwork_explorer_filter`
+-- ---------------------------------------------------------------------
+CREATE TABLE IF NOT EXISTS `tnetwork_explorer_filter` (
+  `id` INT NOT NULL,
+  `filter_name` VARCHAR(45) NULL,
+  `top` VARCHAR(45) NULL,
+  `action` VARCHAR(45) NULL,
+  `advanced_filter` TEXT NULL,
+  PRIMARY KEY (`id`)
+  ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
+
+-- ---------------------------------------------------------------------
+-- Table `tnetwork_usage_filter`
+-- ---------------------------------------------------------------------
+  CREATE TABLE IF NOT EXISTS `tnetwork_usage_filter` (
+  `id` INT NOT NULL auto_increment,
+  `filter_name` VARCHAR(45) NULL,
+  `top` VARCHAR(45) NULL,
+  `action` VARCHAR(45) NULL,
+  `advanced_filter` TEXT NULL,
+  PRIMARY KEY (`id`)
+  ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
\ No newline at end of file