NetworkinsightController.php 10.4 KB
Newer Older
1
<?php
Franco Fichtner's avatar
Franco Fichtner committed
2

3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
/**
 *    Copyright (C) 2016 Deciso B.V.
 *
 *    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.
 *
 */


namespace OPNsense\Diagnostics\Api;

use \OPNsense\Base\ApiControllerBase;
use \OPNsense\Diagnostics\Netflow;
use \OPNsense\Core\Config;
use \OPNsense\Core\Backend;
use \Phalcon\Filter;

/**
 * Class NetworkinsightController
 * @package OPNsense\Netflow
 */
class NetworkinsightController extends ApiControllerBase
{
    /**
     * request timeserie data to use for reporting
48 49 50 51 52 53
     * @param string $provider provider class name
     * @param string $measure measure [octets, packets, octets_ps, packets_ps]
     * @param string $from_date from timestamp
     * @param string $to_date to timestamp
     * @param string $resolution resolution in seconds
     * @param string $field field name to aggregate
54 55
     * @return array timeseries
     */
Franco Fichtner's avatar
Franco Fichtner committed
56
    public function timeserieAction(
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
        $provider = null,
        $measure = null,
        $from_date = null,
        $to_date = null,
        $resolution = null,
        $field = null,
        $emulation = null
    ) {
        // cleanse input
        $filter = new Filter();
        $provider = $filter->sanitize($provider, "alphanum");
        $measure = $filter->sanitize($measure, "string");
        $from_date = $filter->sanitize($from_date, "int");
        $to_date = $filter->sanitize($to_date, "int");
        $resolution = $filter->sanitize($resolution, "int");
        $field = $filter->sanitize($field, "string");

        $result = array();
        if ($this->request->isGet()) {
            $backend = new Backend();
            // request current data
Franco Fichtner's avatar
Franco Fichtner committed
78 79 80
            $response = $backend->configdRun(
                "netflow aggregate fetch {$provider} {$from_date} {$to_date} {$resolution} {$field}"
            );
81
            // for test, request random data
Franco Fichtner's avatar
Franco Fichtner committed
82 83 84 85
            //$response = $backend->configdRun(
            //    "netflow aggregate fetch {$provider} {$from_date} {$to_date} {$resolution} {$field} " .
            //    "em0,in~em0,out~em1,in~em1,out~em2,in~em2,out~em3,in~em3,out"
            //);
86 87 88 89
            $graph_data = json_decode($response, true);
            if ($graph_data != null) {
                ksort($graph_data);
                $timeseries = array();
90 91 92 93
                foreach ($graph_data as $timeserie => $timeserie_data) {
                    foreach ($timeserie_data as $timeserie_key => $payload) {
                        if (!isset($timeseries[$timeserie_key])) {
                            $timeseries[$timeserie_key] = array();
94 95 96 97 98 99 100 101 102
                        }
                        // measure value
                        $measure_val = 0;
                        if ($measure == "octets") {
                            $measure_val = $payload['octets'];
                        } elseif ($measure == "packets") {
                            $measure_val = $payload['packets'];
                        } elseif ($measure == "octets_ps") {
                            $measure_val = $payload['octets'] / $payload['resolution'];
103 104
                        } elseif ($measure == "bps") {
                            $measure_val = ($payload['octets'] / $payload['resolution']) * 8;
105 106 107 108
                        } elseif ($measure == "packets_ps") {
                            $measure_val = $payload['packets'] / $payload['resolution'];
                        }
                        // add to timeseries
109
                        $timeseries[$timeserie_key][] = array((int)$timeserie*1000, $measure_val);
110 111
                    }
                }
112 113
                foreach ($timeseries as $timeserie_key => $data) {
                    $result[] = array("key" => $timeserie_key, "values" => $data);
114 115 116 117 118
                }
            }
        }
        return $result;
    }
119

120 121 122 123 124 125 126 127 128 129
    /**
     * request top usage data (for reporting), values can optionally be filtered using filter_field and filter_value
     * @param string $provider provider class name
     * @param string $from_date from timestamp
     * @param string $to_date to timestamp
     * @param string $field field name(s) to aggregate
     * @param string $measure measure [octets, packets]
     * @param string $max_hits maximum number of results
     * @return array timeseries
     */
Franco Fichtner's avatar
Franco Fichtner committed
130
    public function topAction(
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
        $provider = null,
        $from_date = null,
        $to_date = null,
        $field = null,
        $measure = null,
        $max_hits = null
    ) {
        // cleanse input
        $filter = new Filter();
        $provider = $filter->sanitize($provider, "alphanum");
        $from_date = $filter->sanitize($from_date, "int");
        $to_date = $filter->sanitize($to_date, "int");
        $field = $filter->sanitize($field, "string");
        $measure = $filter->sanitize($measure, "string");
        $max_hits = $filter->sanitize($max_hits, "int");

        $result = array();
        if ($this->request->isGet()) {
            if ($this->request->get("filter_field") != null && $this->request->get("filter_value") != null) {
150 151 152 153 154 155 156 157
                $filter_fields = explode(',', $this->request->get("filter_field"));
                $filter_values = explode(',', $this->request->get("filter_value"));
                $data_filter="";
                foreach ($filter_fields as $field_indx => $filter_field) {
                    if ($data_filter != '') {
                        $data_filter .= ',';
                    }
                    if (isset($filter_values[$field_indx])) {
158
                        $data_filter .= $filter_field.'='.$filter_values[$field_indx];
159 160 161
                    }
                }
                $data_filter = "'{$data_filter}'";
162
            } else {
163 164
                // no filter, empty parameter
                $data_filter = "''";
165 166 167 168
            }
            $backend = new Backend();
            $configd_cmd = "netflow aggregate top {$provider} {$from_date} {$to_date} {$field}";
            $configd_cmd .= " {$measure} {$data_filter} {$max_hits}";
Ad Schellevis's avatar
Ad Schellevis committed
169
            $response = $backend->configdRun($configd_cmd);
170 171 172 173 174
            $graph_data = json_decode($response, true);
            if ($graph_data != null) {
                return $graph_data;
            }
        }
175
        return array();
176 177
    }

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
    /**
     * get metadata from backend aggregation process
     * @return array timeseries
     */
    public function getMetadataAction()
    {
        if ($this->request->isGet()) {
            $backend = new Backend();
            $configd_cmd = "netflow aggregate metadata json";
            $response = $backend->configdRun($configd_cmd);
            $metadata = json_decode($response, true);
            if ($metadata != null) {
                return $metadata;
            }
        }
        return array();
    }

196 197 198 199 200 201 202 203 204 205 206 207 208 209
    /**
     * return interface map (device / name)
     * @return array interfaces
     */
    public function getInterfacesAction()
    {
        // map physical interfaces to description / name
        $configObj = Config::getInstance()->object();
        $allInterfaces = array();
        foreach ($configObj->interfaces->children() as $key => $intf) {
            $allInterfaces[(string)$intf->if] = empty($intf->descr) ? $key : (string)$intf->descr;
        }
        return $allInterfaces;
    }
210 211 212 213 214 215 216

    /**
     * return known protocols
     */
    public function getProtocolsAction()
    {
        $result = array();
Franco Fichtner's avatar
Franco Fichtner committed
217
        foreach (explode("\n", file_get_contents('/etc/protocols')) as $line) {
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
            if (strlen($line) > 1 && $line[0] != '#') {
                $parts = preg_split('/\s+/', $line);
                if (count($parts) >= 4) {
                    $result[$parts[1]] = $parts[0];
                }
            }
        }
        return $result;
    }

    /**
     * return known services
     */
    public function getServicesAction()
    {
        $result = array();
Franco Fichtner's avatar
Franco Fichtner committed
234
        foreach (explode("\n", file_get_contents('/etc/services')) as $line) {
235 236 237 238 239 240 241 242 243 244 245 246
            if (strlen($line) > 1 && $line[0] != '#') {
                // there a few ports which have different names for different protocols, but to not overcomplicate
                // things here, we ignore those exceptions.
                $parts = preg_split('/\s+/', $line);
                if (count($parts) >= 2) {
                    $portnum = explode('/', trim($parts[1]))[0];
                    $result[$portnum] = $parts[0];
                }
            }
        }
        return $result;
    }
247 248 249 250 251 252 253 254 255

    /**
     * request timeserie data to use for reporting
     * @param string $provider provider class name
     * @param string $from_date from timestamp
     * @param string $to_date to timestamp
     * @param string $resolution resolution in seconds
     * @return string csv output
     */
Franco Fichtner's avatar
Franco Fichtner committed
256
    public function exportAction(
257 258 259 260 261 262 263
        $provider = null,
        $from_date = null,
        $to_date = null,
        $resolution = null
    ) {
        $this->response->setContentType('application/CSV', 'UTF-8');
        $this->response->setHeader(
Franco Fichtner's avatar
Franco Fichtner committed
264 265 266
            'Content-Disposition:',
            "Attachment; filename=\"" . $provider . ".csv\""
        );
267 268
        if ($this->request->isGet()) {
            $backend = new Backend();
269
            $configd_cmd = "netflow aggregate export {$provider} {$from_date} {$to_date} {$resolution}";
270 271 272 273 274 275
            $response = $backend->configdRun($configd_cmd);
            return $response;
        } else {
            return "";
        }
    }
276
}