From 83ccec43305ab99013c1a268d37811de4fe4fac9 Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Mon, 13 Mar 2023 21:40:10 +0100 Subject: [PATCH] Interfaces: Diagnostics: Ping - refactor diagnostics tool (https://github.com/opnsense/core/issues/6378) --- plist | 8 +- .../Diagnostics/Api/PingController.php | 131 ++++++++++++ .../OPNsense/Diagnostics/PingController.php | 46 +++++ .../OPNsense/Diagnostics/forms/ping.xml | 41 ++++ .../mvc/app/models/OPNsense/Core/ACL/ACL.xml | 3 +- .../app/models/OPNsense/Core/Menu/Menu.xml | 2 +- .../app/models/OPNsense/Diagnostics/Ping.php | 36 ++++ .../app/models/OPNsense/Diagnostics/Ping.xml | 40 ++++ .../app/views/OPNsense/Diagnostics/ping.volt | 138 +++++++++++++ src/opnsense/scripts/interfaces/ping.py | 190 ++++++++++++++++++ .../conf/actions.d/actions_interface.conf | 30 +++ src/www/diag_ping.php | 157 --------------- 12 files changed, 662 insertions(+), 160 deletions(-) create mode 100644 src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/Api/PingController.php create mode 100644 src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/PingController.php create mode 100644 src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/forms/ping.xml create mode 100644 src/opnsense/mvc/app/models/OPNsense/Diagnostics/Ping.php create mode 100644 src/opnsense/mvc/app/models/OPNsense/Diagnostics/Ping.xml create mode 100644 src/opnsense/mvc/app/views/OPNsense/Diagnostics/ping.volt create mode 100755 src/opnsense/scripts/interfaces/ping.py delete mode 100644 src/www/diag_ping.php diff --git a/plist b/plist index adfb24c63..da952c1b7 100644 --- a/plist +++ b/plist @@ -293,6 +293,7 @@ /usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/Api/NetflowController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/Api/NetworkinsightController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/Api/PacketCaptureController.php +/usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/Api/PingController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/Api/SystemController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/Api/SystemhealthController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/Api/TrafficController.php @@ -303,12 +304,14 @@ /usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/NetflowController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/NetworkinsightController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/PacketCaptureController.php +/usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/PingController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/SystemController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/SystemhealthController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/TrafficController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/forms/dns_diagnostics.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/forms/netflow_capture.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/forms/packetcapture.xml +/usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/forms/ping.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Firewall/AliasController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Firewall/AliasUtilController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/AliasController.php @@ -579,6 +582,8 @@ /usr/local/opnsense/mvc/app/models/OPNsense/Diagnostics/Netflow.xml /usr/local/opnsense/mvc/app/models/OPNsense/Diagnostics/PacketCapture.php /usr/local/opnsense/mvc/app/models/OPNsense/Diagnostics/PacketCapture.xml +/usr/local/opnsense/mvc/app/models/OPNsense/Diagnostics/Ping.php +/usr/local/opnsense/mvc/app/models/OPNsense/Diagnostics/Ping.xml /usr/local/opnsense/mvc/app/models/OPNsense/Dnsmasq/ACL/ACL.xml /usr/local/opnsense/mvc/app/models/OPNsense/Dnsmasq/Menu/Menu.xml /usr/local/opnsense/mvc/app/models/OPNsense/Firewall/Alias.php @@ -688,6 +693,7 @@ /usr/local/opnsense/mvc/app/views/OPNsense/Diagnostics/netflow.volt /usr/local/opnsense/mvc/app/views/OPNsense/Diagnostics/networkinsight.volt /usr/local/opnsense/mvc/app/views/OPNsense/Diagnostics/packetcapture.volt +/usr/local/opnsense/mvc/app/views/OPNsense/Diagnostics/ping.volt /usr/local/opnsense/mvc/app/views/OPNsense/Diagnostics/routes.volt /usr/local/opnsense/mvc/app/views/OPNsense/Diagnostics/systemactivity.volt /usr/local/opnsense/mvc/app/views/OPNsense/Diagnostics/traffic.volt @@ -890,6 +896,7 @@ /usr/local/opnsense/scripts/interfaces/list_sockstat.py /usr/local/opnsense/scripts/interfaces/macinfo.py /usr/local/opnsense/scripts/interfaces/mpd.script +/usr/local/opnsense/scripts/interfaces/ping.py /usr/local/opnsense/scripts/interfaces/ppp-linkdown.sh /usr/local/opnsense/scripts/interfaces/ppp-linkup.sh /usr/local/opnsense/scripts/interfaces/ppp-uptime.sh @@ -1898,7 +1905,6 @@ /usr/local/www/diag_confbak.php /usr/local/www/diag_defaults.php /usr/local/www/diag_logs_settings.php -/usr/local/www/diag_ping.php /usr/local/www/diag_testport.php /usr/local/www/diag_traceroute.php /usr/local/www/fbegin.inc diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/Api/PingController.php b/src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/Api/PingController.php new file mode 100644 index 000000000..d8cce12ad --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/Api/PingController.php @@ -0,0 +1,131 @@ +getModel(); + $result['result'] = 'ok'; + $result['uuid'] = $mdl->settings->generateUUID(); + @mkdir(self::$ping_dir); + $nodes = $mdl->settings->getNodes(); + foreach ($nodes as $key => $value) { + if (is_array($value)) { + $items = []; + foreach ($value as $itemkey => $itemval) { + if (!empty($itemval['selected'])) { + $items[] = $itemkey; + } + } + $nodes[$key] = implode(',', $items); + } + } + file_put_contents( + sprintf('%s/%s.json', self::$ping_dir, $result['uuid']), + json_encode($nodes) + ); + } + return $result; + } + + /** + * start ping job + */ + public function startAction($jobid) + { + $result = ['status' => 'failed']; + if ($this->request->isPost()) { + $this->sessionClose(); + $payload = json_decode((new Backend())->configdpRun('interface ping start', [$jobid]) ?? '', true); + if (!empty($payload)) { + $result = $payload; + } + } + return $result; + } + + /** + * stop ping job + */ + public function stopAction($jobid) + { + $result = ['status' => 'failed']; + if ($this->request->isPost()) { + $this->sessionClose(); + $payload = json_decode((new Backend())->configdpRun('interface ping stop', [$jobid]) ?? '', true); + if (!empty($payload)) { + $result = $payload; + } + } + return $result; + } + + /** + * remove ping job + */ + public function removeAction($jobid) + { + $result = ['status' => 'failed']; + if ($this->request->isPost()) { + $this->sessionClose(); + $payload = json_decode((new Backend())->configdpRun('interface ping remove', [$jobid]) ?? '', true); + if (!empty($payload)) { + $result = $payload; + } + } + return $result; + } + + /** + * search current ping jobs + */ + public function searchJobsAction() + { + $this->sessionClose(); + $data = json_decode((new Backend())->configdRun('interface ping list') ?? '', true); + $records = (!empty($data) && !empty($data['jobs'])) ? $data['jobs'] : []; + return $this->searchRecordsetBase($records); + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/PingController.php b/src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/PingController.php new file mode 100644 index 000000000..3488d9a89 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/PingController.php @@ -0,0 +1,46 @@ +view->pick('OPNsense/Diagnostics/ping'); + $this->view->pingForm = $this->getForm("ping"); + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/forms/ping.xml b/src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/forms/ping.xml new file mode 100644 index 000000000..bb95ccf27 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/forms/ping.xml @@ -0,0 +1,41 @@ +
+ + ping.settings.hostname + + text + + + + ping.settings.fam + + dropdown + + + ping.settings.source_address + + text + + + + ping.settings.packetsize + + text + + + + ping.settings.disable_frag + + checkbox + + Disable fragmentation. + Can be helpful to determine the maximum size a transport is able to send. + Keep in mind this is the payload size, an IP and ICMP header are added. + + + + ping.settings.description + + text + Description to be displayed in the "jobs" tab. + +
diff --git a/src/opnsense/mvc/app/models/OPNsense/Core/ACL/ACL.xml b/src/opnsense/mvc/app/models/OPNsense/Core/ACL/ACL.xml index 8e2e19fcc..6f9a49c05 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Core/ACL/ACL.xml +++ b/src/opnsense/mvc/app/models/OPNsense/Core/ACL/ACL.xml @@ -166,7 +166,8 @@ Diagnostics: Ping - diag_ping.php* + ui/diagnostics/ping + api/diagnostics/ping/* diff --git a/src/opnsense/mvc/app/models/OPNsense/Core/Menu/Menu.xml b/src/opnsense/mvc/app/models/OPNsense/Core/Menu/Menu.xml index 758ea4dcc..fd1eaf5dd 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Core/Menu/Menu.xml +++ b/src/opnsense/mvc/app/models/OPNsense/Core/Menu/Menu.xml @@ -134,7 +134,7 @@ - + diff --git a/src/opnsense/mvc/app/models/OPNsense/Diagnostics/Ping.php b/src/opnsense/mvc/app/models/OPNsense/Diagnostics/Ping.php new file mode 100644 index 000000000..9126487c0 --- /dev/null +++ b/src/opnsense/mvc/app/models/OPNsense/Diagnostics/Ping.php @@ -0,0 +1,36 @@ + + :memory: + 1.0.0 + + OPNsense Ping Diagnostics + + + + + Y + Provide a valid hostname or address to ping + + + Y + ip + + IPv4 + IPv6 + + + + N + N + Provide a valid source address + + + 1 + 65535 + + + 0 + + + N + /^(.){1,255}$/u + Description should be a string between 1 and 255 characters + + + + diff --git a/src/opnsense/mvc/app/views/OPNsense/Diagnostics/ping.volt b/src/opnsense/mvc/app/views/OPNsense/Diagnostics/ping.volt new file mode 100644 index 000000000..f72c70791 --- /dev/null +++ b/src/opnsense/mvc/app/views/OPNsense/Diagnostics/ping.volt @@ -0,0 +1,138 @@ +{# + # Copyright (c) 2023 Deciso B.V. + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or withoutmodification, + # 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. + #} + + + + + + +
+
+
+ {{ partial("layout_partials/base_form",['fields':pingForm,'id':'frm_PingSettings', 'apply_btn_id':'btn_start_new'])}} +
+
+
+ + + + + + + + + + + + + + + + + + + + +
 {{ lang._('ID') }}{{ lang._('Description') }}{{ lang._('Hostname') }}{{ lang._('Source') }}{{ lang._('Send') }}{{ lang._('Received') }}{{ lang._('Min') }}{{ lang._('Max') }}{{ lang._('Avg') }}{{ lang._('loss') }}{{ lang._('Error') }}{{ lang._('Commands') }}
+
+
diff --git a/src/opnsense/scripts/interfaces/ping.py b/src/opnsense/scripts/interfaces/ping.py new file mode 100755 index 000000000..302c5c5b1 --- /dev/null +++ b/src/opnsense/scripts/interfaces/ping.py @@ -0,0 +1,190 @@ +#!/usr/local/bin/python3 + +""" + Copyright (c) 2023 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. + +""" + +TEMP_DIR = '/tmp/ping/' + +import argparse +import collections +import glob +import subprocess +import os +import ujson +import sys +sys.path.insert(0, "/usr/local/opnsense/site-python") +from log_helper import reverse_log_reader + + +def ping_pids(jobid): + """ search for capture pids using output filename + :param jobid: job uuid number + :return: list of pids + """ + pids = [] + args = ['/bin/pgrep', '-af', "ping_%s" % jobid] + for line in subprocess.run(args, capture_output=True, text=True).stdout.split(): + if line.isdigit(): + pids.append(line) + return pids + + +def load_settings(filename): + try: + return ujson.load(open(filename, 'r')) + except ValueError: + return {} + + +def read_latest_stats(filename): + result = { + 'loss': None, + 'send': None, + 'received': None, + 'min': None, + 'max': None, + 'avg': None, + 'std-dev': None, + 'last_error': None + } + next_break = False + if os.path.isfile(filename): + items = collections.deque(maxlen=5) + for line in reverse_log_reader(filename): + line = line['line'] + if line.startswith('ping:'): + result['last_error'] = line[6:].strip() + if next_break: + break + items.append(line) + if line.endswith('packet loss'): + if next_break: + break + # IPv6 + for item in items: + parts = item.split() + if item.endswith('packet loss') and len(parts) >=6: + result['loss'] = parts[6] + result['send'] = int(parts[0]) + result['received'] = int(parts[3]) + elif item.startswith('round-trip') and len(parts) >= 4 and parts[3].count('/') == 3: + stats = parts[3].split('/') + result['min'] = float(stats[0]) + result['avg'] = float(stats[1]) + result['max'] = float(stats[2]) + result['std-dev'] = float(stats[3]) + next_break=True + elif line.find('packets received') > -1: + if next_break: + break + # IPv4 + parts = items[-1].split() + if parts[0].find('/') > 0: + result['send'] = int(parts[0].split('/')[1]) + result['received'] = int(parts[0].split('/')[0]) + if len(parts) >= 12: + if parts[5] == 'min': + result['min'] = float(parts[4]) + if parts[8] == 'avg': + result['avg'] = float(parts[7]) + if parts[11] == 'max': + result['max'] = float(parts[10]) + if result['send']: + loss = (result['send']-result['received']) / result['send'] * 100.0 + result['loss'] = "%0.2f %%" % loss + next_break=True + return result + + +if __name__ == '__main__': + result = dict() + parser = argparse.ArgumentParser() + parser.add_argument('--job', help='job id', default=None) + parser.add_argument('action', help='action to perfom', choices=['list', 'start', 'stop', 'remove', 'view']) + cmd_args = parser.parse_args() + + all_jobs = {} + if os.path.exists(TEMP_DIR): + for filename in glob.glob("%s*.json" % TEMP_DIR): + all_jobs[os.path.basename(filename).split('.')[0]] = filename + + if cmd_args.action == 'list': + result['jobs'] = [] + result['status'] = 'ok' + for jobid in all_jobs: + this_pids = ping_pids(jobid) + if len(this_pids) > 0: + with open("%s.pid" % all_jobs[jobid][:-5], 'r') as f_in: + subprocess.run(['kill', '-s', 'INFO', f_in.read().strip()]) + settings = load_settings(all_jobs[jobid]) + settings['id'] = jobid + settings['status'] = "running" if len(this_pids) > 0 else "stopped" + # merge stats + settings.update(read_latest_stats("%s.log" % all_jobs[jobid][:-5])) + result['jobs'].append(settings) + elif cmd_args.action == 'start' and cmd_args.job in all_jobs: + this_pids = ping_pids(cmd_args.job) + if len(this_pids) > 0: + result['status'] = 'failed' + result['status_msg'] = 'already active (pids: %s)' % ','.join(this_pids) + else: + result['status'] = 'ok' + settings = load_settings(all_jobs[cmd_args.job]) + log_target = "%s%s.log" % (TEMP_DIR, cmd_args.job) + args = [ + '/usr/sbin/daemon', + '-o', log_target, + '-p', "%s%s.pid" % (TEMP_DIR, cmd_args.job), + '-t', 'ping_%s' % cmd_args.job, + '/sbin/ping', + '-4' if settings.get('fam', 'ip') == 'ip' else '-6' + ] + if settings.get('packetsize', '') != '': + args.append('-s') + args.append(settings['packetsize']) + if settings.get('disable_frag', '0') == '1': + args.append('-D') + args.append(settings.get('hostname', '')) + if os.path.isfile(log_target): + os.remove(log_target) + subprocess.run(args) + elif cmd_args.action == 'stop' and cmd_args.job in all_jobs: + result['status'] = 'ok' + result['stopped_processes'] = 0 + for pid in ping_pids(cmd_args.job): + subprocess.run(['kill', pid]) + result['stopped_processes'] += 1 + elif cmd_args.action == 'remove' and cmd_args.job in all_jobs: + result['status'] = 'ok' + result['stopped_processes'] = 0 + for pid in ping_pids(cmd_args.job): + subprocess.run(['kill', pid]) + result['stopped_processes'] += 1 + for filename in glob.glob("%s%s*" % (TEMP_DIR, cmd_args.job)): + os.remove(filename) + + print (ujson.dumps(result)) diff --git a/src/opnsense/service/conf/actions.d/actions_interface.conf b/src/opnsense/service/conf/actions.d/actions_interface.conf index 0c53bd9d2..e6899117e 100644 --- a/src/opnsense/service/conf/actions.d/actions_interface.conf +++ b/src/opnsense/service/conf/actions.d/actions_interface.conf @@ -237,3 +237,33 @@ command:/usr/local/opnsense/scripts/interfaces/macinfo.py parameters: %s type:script_output message:fetch mac info for %s + +[ping.list] +command:/usr/local/opnsense/scripts/interfaces/ping.py list +parameters: +type:script_output +message:Show current ping jobs + +[ping.start] +command:/usr/local/opnsense/scripts/interfaces/ping.py +parameters: --job %s start +type:script_output +message:Start ping jobid %s + +[ping.stop] +command:/usr/local/opnsense/scripts/interfaces/ping.py +parameters: --job %s stop +type:script_output +message:Stop ping jobid %s + +[ping.remove] +command:/usr/local/opnsense/scripts/interfaces/ping.py +parameters: --job %s remove +type:script_output +message:Remove ping jobid %s + +[ping.view] +command:/usr/local/opnsense/scripts/interfaces/ping.py +parameters: --job %s --detail %s view +type:script_output +message:View ping jobid %s (%s) diff --git a/src/www/diag_ping.php b/src/www/diag_ping.php deleted file mode 100644 index 154cf2982..000000000 --- a/src/www/diag_ping.php +++ /dev/null @@ -1,157 +0,0 @@ - - * Copyright (C) 2016 Deciso B.V. - * Copyright (C) 2003-2005 Bob Zoller - * Copyright (C) 2003-2005 Manuel Kasper - * 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. - */ - -require_once("guiconfig.inc"); -require_once("system.inc"); -require_once("interfaces.inc"); - -$cmd_output = false; -if ($_SERVER['REQUEST_METHOD'] === 'GET') { - // set form defaults - $pconfig = array(); - $pconfig['count'] = isset($_GET['count']) ? $_GET['count'] : 3; - $pconfig['host'] = isset($_GET['host']) ? $_GET['host'] : null; - $pconfig['interface'] = isset($_GET['interface']) ? $_GET['interface'] : null; -} elseif ($_SERVER['REQUEST_METHOD'] === 'POST') { - // validate formdata and schedule action - $pconfig = $_POST; - $input_errors = array(); - /* input validation */ - $reqdfields = explode(" ", "host count"); - $reqdfieldsn = array(gettext("Host"),gettext("Count")); - do_input_validation($pconfig, $reqdfields, $reqdfieldsn, $input_errors); - - if (count($input_errors) == 0) { - $args = []; - switch ($pconfig['ipproto']) { - case 'ipv6': - list ($ifaddr) = interfaces_primary_address6($pconfig['interface']); - $args[] = '-6'; - break; - case 'ipv6-ll': - $args[] = '-6'; - list ($ifaddr) = interfaces_scoped_address6($pconfig['interface']); - break; - default: - $args[] = '-4'; - list ($ifaddr) = interfaces_primary_address($pconfig['interface']); - break; - } - if (!empty($ifaddr)) { - $args[] = exec_safe('-S %s ', $ifaddr); - } - $args[] = exec_safe('-c %s %s', [$pconfig['count'], $pconfig['host']]); - // execute ping command and catch both stdout and stderr - $cmd_action = '/sbin/ping ' . implode(' ', $args); - $process = proc_open($cmd_action, array(array("pipe", "r"), array("pipe", "w"), array("pipe", "w")), $pipes); - if (is_resource($process)) { - $cmd_output = "# $cmd_action\n"; - $cmd_output .= stream_get_contents($pipes[1]); - $cmd_output .= stream_get_contents($pipes[2]); - } - } -} - -legacy_html_escape_form_data($pconfig); -include("head.inc"); ?> - - - -
-
-
-
- 0) print_input_errors($input_errors); ?> -
-
-
- - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
 
-
-
-
-
- -
-
-
- -
-
-
-