From 56e6924bb623d5e45c0dbde76b465686afea8bde Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Sun, 6 Sep 2015 17:49:27 +0000 Subject: [PATCH] (legacy) refactor diag_states_summary.php --- src/opnsense/scripts/filter/list_states.py | 108 +++++++ .../conf/actions.d/actions_filter.conf | 6 + src/www/diag_states_summary.php | 301 ++++++++---------- 3 files changed, 245 insertions(+), 170 deletions(-) create mode 100755 src/opnsense/scripts/filter/list_states.py diff --git a/src/opnsense/scripts/filter/list_states.py b/src/opnsense/scripts/filter/list_states.py new file mode 100755 index 000000000..89de711b8 --- /dev/null +++ b/src/opnsense/scripts/filter/list_states.py @@ -0,0 +1,108 @@ +#!/usr/local/bin/python2.7 + +""" + Copyright (c) 2015 Ad Schellevis + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + -------------------------------------------------------------------------------------- + list pf states +""" +import tempfile +import subprocess +import os +import sys +import ujson + +def parse_address(addr): + result = {'port':'0'} + if addr.count(':') > 1: + # parse IPv6 address + result['addr'] = addr.split('[')[0] + result['ipproto'] = 'ipv6' + if addr.find('[') > -1: + result['port'] = addr.split('[')[1].split(']')[0] + else: + # parse IPv4 address + result['ipproto'] = 'ipv4' + result['addr'] = addr.split(':')[0] + if addr.find(':') > -1: + result['port'] = addr.split(':')[1] + + return result + +if __name__ == '__main__': + result={'details':[]} + with tempfile.NamedTemporaryFile() as output_stream: + subprocess.call(['/sbin/pfctl','-s', 'state'], stdout=output_stream, stderr=open(os.devnull, 'wb')) + output_stream.seek(0) + data = output_stream.read().strip() + if (data.count('\n') > 2): + for line in data.split('\n'): + parts = line.split() + if len(parts) >= 6: + record = {} + record['nat_addr'] = None + record['nat_port'] = None + record['iface'] = parts[0] + record['proto'] = parts[1] + record['src_addr'] = parse_address(parts[2])['addr'] + record['src_port'] = parse_address(parts[2])['port'] + record['ipproto'] = parse_address(parts[2])['ipproto'] + + if parts[3].find('(') > -1: + # NAT enabled + record['nat_addr'] = parts[3][1:].split(':')[0] + record['nat_port'] = parts[3].split(':')[1][:-1] + + record['dst_addr'] = parse_address(parts[-2])['addr'] + record['dst_port'] = parse_address(parts[-2])['port'] + + if parts[-3] == '->': + record['direction'] = 'out' + else: + record['direction'] = 'in' + + record['state'] = parts[-1] + + result['details'].append(record) + + result['total'] = len(result['details']) + + # handle command line argument (type selection) + if len(sys.argv) > 1 and sys.argv[1] == 'json': + print(ujson.dumps(result)) + else: + # output plain + print ('------------------------- STATES -------------------------') + for state in result['details']: + if state['ipproto'] == 'ipv4': + if state['nat_addr'] is not None: + print ('%(iface)s %(proto)s %(src_addr)s:%(src_port)s \ + (%(nat_addr)s:%(nat_port)s) %(direction)s %(dst_addr)s:%(dst_port)s %(state)s'%state) + else: + print ('%(iface)s %(proto)s %(src_addr)s:%(src_port)s \ + %(direction)s %(dst_addr)s:%(dst_port)s %(state)s'%state) + else: + print ('%(iface)s %(proto)s %(src_addr)s[%(src_port)s] \ + %(direction)s %(dst_addr)s[%(dst_port)s] %(state)s'%state) diff --git a/src/opnsense/service/conf/actions.d/actions_filter.conf b/src/opnsense/service/conf/actions.d/actions_filter.conf index 75c5436cd..10d56d07c 100644 --- a/src/opnsense/service/conf/actions.d/actions_filter.conf +++ b/src/opnsense/service/conf/actions.d/actions_filter.conf @@ -34,6 +34,12 @@ parameters: %s %s type:script_output message:request content of pf %s table +[list.states] +command:/usr/local/opnsense/scripts/filter/list_states.py +parameters: %s +type:script_output +message:request pf states + [delete.table] command:/usr/local/opnsense/scripts/filter/delete_table.py parameters: %s %s diff --git a/src/www/diag_states_summary.php b/src/www/diag_states_summary.php index 2d5228f5c..0ddbf6062 100644 --- a/src/www/diag_states_summary.php +++ b/src/www/diag_states_summary.php @@ -1,205 +1,166 @@ 0, "protos" => array()); + } + if (!isset($iparr[$ip]['protos'][$proto])) { + $iparr[$ip]['protos'][$proto] = array("seen" => 0, 'srcports' => array(), 'dstports' => array()); + } + $iparr[$ip]['seen']++; + $iparr[$ip]['protos'][$proto]['seen']++; + if (!empty($srcport)) { + if (!isset($iparr[$ip]['protos'][$proto]['srcports'][$srcport])) { + $iparr[$ip]['protos'][$proto]['srcports'][$srcport] = 0; + } + $iparr[$ip]['protos'][$proto]['srcports'][$srcport]++; + } + if (!empty($dstport)) { + $iparr[$ip]['protos'][$proto]['dstports'][$dstport]++; + } +} + +function sort_by_ip($a, $b) { + return ip2ulong($a) < ip2ulong($b) ? -1 : 1; +} + +function build_port_info($portarr, $proto) { + if (empty($portarr)) { + return ''; + } + $ports = array(); + asort($portarr); + foreach (array_reverse($portarr, TRUE) as $port => $count) { + $str = ""; + $service = getservbyport($port, strtolower($proto)); + $port = "{$proto}/{$port}"; + if (!empty($service)) { + $port = "{$port} ({$service})"; + } + $ports[] = "{$port}: {$count}"; + } + return implode($ports, ', '); +} $srcipinfo = array(); $dstipinfo = array(); $allipinfo = array(); $pairipinfo = array(); -function addipinfo(&$iparr, $ip, $proto, $srcport, $dstport) { - $iparr[$ip]['seen']++; - $iparr[$ip]['protos'][$proto]['seen']++; - if (!empty($srcport)) { - $iparr[$ip]['protos'][$proto]['srcports'][$srcport]++; - } - if (!empty($dstport)) { - $iparr[$ip]['protos'][$proto]['dstports'][$dstport]++; - } +$states = json_decode(configd_run("filter list states json"), true); +if(isset($states['details'])) { + foreach($states['details'] as $state) { + if (isset($state['nat_addr']) && $states['direction'] == 'out') { + $srcip = $state['nat_addr'] ; + $srcport = $state['nat_port'] ; + } else { + $srcip = $state['src_addr'] ; + $srcport = $state['src_port'] ; + } + $dstip = $state['dst_addr'] ; + $dstport = $state['dst_port'] ; + $proto = $state['proto']; + + addipinfo($srcipinfo, $srcip, $proto, $srcport, $dstport); + addipinfo($dstipinfo, $dstip, $proto, $srcport, $dstport); + addipinfo($pairipinfo, "{$srcip} -> {$dstip}", $proto, $srcport, $dstport); + + addipinfo($allipinfo, $srcip, $proto, $srcport, $dstport); + addipinfo($allipinfo, $dstip, $proto, $srcport, $dstport); + + } } -$row = 0; -if(count($states) > 0) { - foreach($states as $line) { - $line_split = preg_split("/\s+/", $line); - $iface = array_shift($line_split); - $proto = array_shift($line_split); - $state = array_pop($line_split); - $info = implode(" ", $line_split); - - /* Handle NAT cases - Replaces an external IP + NAT by the internal IP */ - if (strpos($info, ') ->') !== FALSE) { - /* Outbound NAT */ - $info = preg_replace('/(\S+) \((\S+)\)/U', "$2", $info); - } elseif (strpos($info, ') <-') !== FALSE) { - /* Inbound NAT/Port Forward */ - $info = preg_replace('/(\S+) \((\S+)\)/U', "$1", $info); - } - - /* break up info and extract $srcip and $dstip */ - $ends = preg_split("/\?/", $info); - - if (strpos($info, '->') === FALSE) { - $srcinfo = $ends[count($ends) - 1]; - $dstinfo = $ends[0]; - } else { - $srcinfo = $ends[0]; - $dstinfo = $ends[count($ends) - 1]; - } - - /* Handle IPv6 */ - $parts = explode(":", $srcinfo); - $partcount = count($parts); - if ($partcount <= 2) { - $srcip = trim($parts[0]); - $srcport = trim($parts[1]); - } else { - preg_match("/([0-9a-f:]+)(\[([0-9]+)\])?/i", $srcinfo, $matches); - $srcip = $matches[1]; - $srcport = trim($matches[3]); - } - - $parts = explode(":", $dstinfo); - $partcount = count($parts); - if ($partcount <= 2) { - $dstip = trim($parts[0]); - $dstport = trim($parts[1]); - } else { - preg_match("/([0-9a-f:]+)(\[([0-9]+)\])?/i", $dstinfo, $matches); - $dstip = $matches[1]; - $dstport = trim($matches[3]); - } - - addipinfo($srcipinfo, $srcip, $proto, $srcport, $dstport); - addipinfo($dstipinfo, $dstip, $proto, $srcport, $dstport); - addipinfo($pairipinfo, "{$srcip} -> {$dstip}", $proto, $srcport, $dstport); - - addipinfo($allipinfo, $srcip, $proto, $srcport, $dstport); - addipinfo($allipinfo, $dstip, $proto, $srcport, $dstport); - - } -} - -function sort_by_ip($a, $b) { - return ip2ulong($a) < ip2ulong($b) ? -1 : 1; -} - -function build_port_info($portarr, $proto) { - if (!$portarr) - return ''; - $ports = array(); - asort($portarr); - foreach (array_reverse($portarr, TRUE) as $port => $count) { - $str = ""; - $service = getservbyport($port, strtolower($proto)); - $port = "{$proto}/{$port}"; - if ($service) - $port = "{$port} ({$service})"; - $ports[] = "{$port}: {$count}"; - } - return implode($ports, ', '); -} - -function print_summary_table($label, $iparr, $sort = TRUE) { ?> -
-
-
-

-
- -
- - - - - - - - - - - $ipinfo) { ?> - - - - - - - - - $protoinfo) { ?> - - - - - - - - - - - -
# #
    
  
-
-
+function print_summary_table($label, $iparr, $sort = TRUE) { + if ($sort) { + uksort($iparr, "sort_by_ip"); + } + ?> +
+
+
+

+
+
+ + + + + + + + + + $ipinfo) { ?> + + + + + + $protoinfo) { ?> + + + + + + + + + +
# #
 
 
+
+
+
"; include("fbegin.inc"); ?>
-
-
- - - +
+
- -
- - + +