id_name)) or filters filtered * * @param mixed Array with filter conditions to retrieve filters or false. * * @return array List of all filters */ function netflow_get_filters ($filter = false) { if ($filter === false) { $filters = db_get_all_rows_in_table ("tnetflow_filter", "id_name"); } else { $filters = db_get_all_rows_filter ("tnetflow_filter", $filter); } $return = array (); if ($filters === false) { return $return; } foreach ($filters as $filter) { $return[$filter["id_name"]] = $filter["id_name"]; } return $return; } /** * Selects all netflow reports (array (id_name => id_name)) or filters filtered * * @param mixed Array with filter conditions to retrieve filters or false. * * @return array List of all filters */ function netflow_get_reports ($filter = false) { if ($filter === false) { $filters = db_get_all_rows_in_table ("tnetflow_report", "id_name"); } else { $filters = db_get_all_rows_filter ("tnetflow_report", $filter); } $return = array (); if ($filters === false) { return $return; } foreach ($filters as $filter) { $return[$filter["id_name"]] = $filter["id_name"]; } return $return; } //permite validar si un filtro pertenece a un grupo permitido para el usuario function netflow_check_filter_group ($id_sg) { global $config; $id_group = db_get_value('id_group', 'tnetflow_filter', 'id_sg', $id_sg); $own_info = get_user_info ($config['id_user']); // Get group list that user has access $groups_user = users_get_groups ($config['id_user'], "IW", $own_info['is_admin'], true); $groups_id = array(); $has_permission = false; foreach($groups_user as $key => $groups){ if ($groups['id_grupo'] == $id_group) return true; } return false; } /* Permite validar si un informe pertenece a un grupo permitido para el usuario. * Si mode = false entonces es modo godmode y solo puede ver el grupo All el admin * Si es modo operation (mode = true) entonces todos pueden ver el grupo All */ function netflow_check_report_group ($id_report, $mode=false) { global $config; if (!$mode) { $own_info = get_user_info ($config['id_user']); $mode = $own_info['is_admin']; } $id_group = db_get_value('id_group', 'tnetflow_report', 'id_report', $id_report); // Get group list that user has access $groups_user = users_get_groups ($config['id_user'], "IW", $mode, true); $groups_id = array(); $has_permission = false; foreach($groups_user as $key => $groups){ if ($groups['id_grupo'] == $id_group) return true; } return false; } /** * Get a filter. * * @param int filter id to be fetched. * @param array Extra filter. * @param array Fields to be fetched. * * @return array A netflow filter matching id and filter. */ function netflow_filter_get_filter ($id_sg, $filter = false, $fields = false) { if (! is_array ($filter)) $filter = array (); $filter['id_sg'] = (int) $id_sg; return db_get_row_filter ('tnetflow_filter', $filter, $fields); } /** * Get options. * * @param int filter id to be fetched. * @param array Extra filter. * @param array Fields to be fetched. * * @return array A netflow filter matching id and filter. */ function netflow_reports_get_reports ($id_report, $filter = false, $fields = false) { if (empty ($id_report)) return false; if (! is_array ($filter)) $filter = array (); $filter['id_report'] = (int) $id_report; return db_get_row_filter ('tnetflow_report', $filter, $fields); } function netflow_reports_get_content ($id_rc, $filter = false, $fields = false){ if (empty ($id_rc)) return false; if (! is_array ($filter)) $filter = array (); $filter['id_rc'] = (int) $id_rc; return db_get_row_filter ('tnetflow_report_content', $filter, $fields); } /** * Compare two flows according to the 'data' column. * * @param array a First flow. * @param array b Second flow. * * @return Result of the comparison. */ function compare_flows ($a, $b) { return $a['data'] < $b['data']; } /** * Sort netflow data according to the 'data' column. * * @param array netflow_data Netflow data array. * */ function sort_netflow_data (&$netflow_data) { usort($netflow_data, "compare_flows"); } /** * Show a table with netflow statistics. * * @param array data Statistic data. * @param string start_date Start date. * @param string end_date End date. * @param string aggregate Aggregate field. * @param string unit Unit to show. * * @return The statistics table. */ function netflow_stat_table ($data, $start_date, $end_date, $aggregate, $unit){ global $nfdump_date_format; $start_date = date ($nfdump_date_format, $start_date); $end_date = date ($nfdump_date_format, $end_date); $values = array(); $table->width = '50%'; $table->cellspacing = 0; $table->class = 'databox'; $table->data = array(); $j = 0; $x = 0; $table->head = array (); $table->head[0] = '' . netflow_format_aggregate ($aggregate) . ''; $table->head[1] = '' . netflow_format_unit ($unit) . ''; $table->style[0] = 'padding: 6px'; $table->style[1] = 'padding: 6px'; while (isset ($data[$j])) { $agg = $data[$j]['agg']; if (!isset($values[$agg])){ $values[$agg] = $data[$j]['data']; $table->data[$x][0] = $agg; $table->data[$x][1] = format_numeric ($data[$j]['data']) . ' ' . netflow_format_unit ($unit); } else { $values[$agg] += $data[$j]['data']; $table->data[$x][0] = $agg; $table->data[$x][1] = format_numeric ($data[$j]['data']) . ' ' . netflow_format_unit ($unit); } $j++; $x++; } return html_print_table ($table, true); } /** * Show a table with netflow data. * * @param array data Netflow data. * @param string start_date Start date. * @param string end_date End date. * @param string aggregate Aggregate field. * * @return The statistics table. */ function netflow_data_table ($data, $start_date, $end_date, $aggregate, $unit) { global $nfdump_date_format; $period = $end_date - $start_date; $start_date = date ($nfdump_date_format, $start_date); $end_date = date ($nfdump_date_format, $end_date); // Set the format if ($period <= SECONDS_6HOURS) { $time_format = 'H:i:s'; } elseif ($period < SECONDS_1DAY) { $time_format = 'H:i'; } elseif ($period < SECONDS_15DAYS) { $time_format = 'M d H:i'; } elseif ($period < SECONDS_1MONTH) { $time_format = 'M d H\h'; } else { $time_format = 'M d H\h'; } $values = array(); $table->size = array ('60%'); $table->class = 'databox'; $table->cellspacing = 0; $table->data = array(); $table->head = array(); $table->head[0] = ''.__('Timestamp').''; $table->style[0] = 'padding: 4px'; $j = 0; $source_index = array (); $source_count = 0; if (isset ($data['sources'])) { foreach ($data['sources'] as $source => $null) { $table->style[$j+1] = 'padding: 4px'; $table->align[$j+1] = "right"; $table->head[$j+1] = $source; $source_index[$j] = $source; $source_count++; $j++; } } else { $table->style[1] = 'padding: 4px;'; } // No aggregates if ($source_count == 0) { $table->head[1] = __('Data'); $table->align[1] = "right"; $i = 0; foreach ($data as $timestamp => $value) { $table->data[$i][0] = date ($time_format, $timestamp); $table->data[$i][1] = format_numeric ($value['data']) . ' ' . netflow_format_unit ($unit); $i++; } } // Aggregates else { $i = 0; foreach ($data['data'] as $timestamp => $values) { $table->data[$i][0] = date ($time_format, $timestamp); for ($j = 0; $j < $source_count; $j++) { if (isset ($values[$source_index[$j]])) { $table->data[$i][$j+1] = format_numeric ($values[$source_index[$j]]) . ' ' . netflow_format_unit ($unit); } else { $table->data[$i][$j+1] = 0 . ' ' . netflow_format_unit ($unit); } } $i++; } } return html_print_table($table, true); } /** * Show a table with a traffic summary. * * @param array data Summary data. * * @return The statistics table. */ function netflow_summary_table ($data) { global $nfdump_date_format; $values = array(); $table->size = array('50%'); $table->cellspacing = 0; $table->class = 'databox'; $table->data = array(); $table->style[0] = 'font-weight: bold; padding: 6px'; $table->style[1] = 'padding: 6px'; $row = array(); $row[] = __('Total flows'); $row[] = format_numeric ($data['totalflows']); $table->data[] = $row; $row = array(); $row[] = __('Total bytes'); $row[] = format_numeric ($data['totalbytes']); $table->data[] = $row; $row = array(); $row[] = __('Total packets'); $row[] = format_numeric ($data['totalpackets']); $table->data[] = $row; $row = array(); $row[] = __('Average bits per second'); $row[] = format_numeric ($data['avgbps']); $table->data[] = $row; $row = array(); $row[] = __('Average packets per second'); $row[] = format_numeric ($data['avgpps']); $table->data[] = $row; $row = array(); $row[] = __('Average bytes per packet'); $row[] = format_numeric ($data['avgbpp']); $table->data[] = $row; $html = html_print_table ($table, true); return $html; } /** * Returns 1 if the given address is a network address. * * @param string address Host or network address. * * @return 1 if the address is a network address, 0 otherwise. * */ function netflow_is_net ($address) { if (strpos ($address, '/') !== FALSE) { return 1; } return 0; } /** * Returns netflow data for the given period in an array. * * @param string start_date Period start date. * @param string end_date Period end date. * @param string filter Netflow filter. * @param string aggregate Aggregate field. * @param int max Maximum number of aggregates. * @param string unit Unit to show. * * @return An array with netflow stats. * */ function netflow_get_data ($start_date, $end_date, $interval_length, $filter, $aggregate, $max, $unit, $connection_name = '', $address_resolution = false) { global $nfdump_date_format; global $config; // Requesting remote data if (defined ('METACONSOLE') && $connection_name != '') { $data = metaconsole_call_remote_api ($connection_name, 'netflow_get_data', "$start_date|$end_date|$interval_length|" . base64_encode(json_encode($filter)) . "|$aggregate|$max|$unit" . (int)$address_resolution); return json_decode ($data, true); } // Calculate the number of intervals if ($interval_length <= 0) { $num_intervals = $config['graph_res'] * 50; $period = $end_date - $start_date; $interval_length = (int) ($period / $num_intervals); } else { $period = $end_date - $start_date; $num_intervals = (int) ($period / $interval_length); } // Set a max number of intervals if ($num_intervals > $config['netflow_max_resolution']) { $num_intervals = $config['netflow_max_resolution']; $interval_length = (int) ($period / $num_intervals); } // If there is aggregation calculate the top n if ($aggregate != 'none') { $values['data'] = array (); $values['sources'] = array (); // Get the command to call nfdump $command = netflow_get_command ($filter); // Suppress the header line and the statistics at the bottom and configure piped output $command .= ' -q -o csv'; // Call nfdump $agg_command = $command . " -n $max -s $aggregate/bytes -t ".date($nfdump_date_format, $start_date).'-'.date($nfdump_date_format, $end_date); exec($agg_command, $string); // Remove the first line $string[0] = ''; // Parse aggregates foreach($string as $line){ if ($line=='') { continue; } $val = explode(',',$line); if ($aggregate == 'proto') { $values['sources'][$val[3]] = 1; } else { $values['sources'][$val[4]] = 1; } } // Update the filter switch ($aggregate) { case "proto": $extra_filter = 'proto'; break; default: case "srcip": $extra_filter = 'ip_src'; break; case "srcport": $extra_filter = 'src_port'; break; case "dstip": $extra_filter = 'ip_dst'; break; case "dstport": $extra_filter = 'dst_port'; break; } if (isset ($filter[$extra_filter]) && $filter[$extra_filter] != '') { $filter[$extra_filter] .= ','; } $filter[$extra_filter] = implode (',', array_keys ($values['sources'])); } else { $values = array (); } // Address resolution start $get_hostnames = false; if ($address_resolution && ($aggregate == "srcip" || $aggregate == "dstip")) { $get_hostnames = true; global $hostnames; $sources = array(); foreach ($values['sources'] as $source => $value) { if (!isset($hostnames[$source])) { $hostname = gethostbyaddr($source); if ($hostname !== false) { $hostnames[$source] = $hostname; $source = $hostname; } } else { $source = $hostnames[$source]; } $sources[$source] = $value; } $values['sources'] = $sources; } // Address resolution end $interval_start = $start_date; for ($i = 0; $i < $num_intervals; $i++, $interval_start+=$interval_length+1) { $interval_end = $interval_start + $interval_length; if ($interval_end > $end_date) { $interval_end = $end_date; } if ($aggregate == 'none') { $data = netflow_get_summary ($interval_start, $interval_end, $filter, $connection_name); if (! isset ($data['totalbytes'])) { $values[$interval_start]['data'] = 0; continue; } switch ($unit) { case 'megabytes': $values[$interval_start]['data'] = $data['totalbytes'] / 1048576; break; case 'megabytespersecond': $values[$interval_start]['data'] = $data['avgbps'] / 1048576 / 8; break; case 'kilobytes': $values[$interval_start]['data'] = $data['totalbytes'] / 1024; break; case 'kilobytespersecond': $values[$interval_start]['data'] = $data['avgbps'] / 1024 / 8; break; default: $values[$interval_start]['data'] = $data['totalbytes']; break; } } else { // Set default values foreach ($values['sources'] as $source => $discard) { $values['data'][$interval_start][$source] = 0; } $data = netflow_get_stats ($interval_start, $interval_end, $filter, $aggregate, $max, $unit, $connection_name); foreach ($data as $line) { // Address resolution start if ($get_hostnames) { if (!isset($hostnames[$line['agg']])) { $hostname = false; // Trying to get something like an IP from the description if (preg_match ("/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/", $line['agg'], $matches) || preg_match ("/(((?=(?>.*?(::))(?!.+\3)))\3?|([\dA-F]{1,4}(\3|:?)|\2))(?4){5}((?4){2}|(25[0-5]| (2[0-4]|1\d|[1-9])?\d)(\.(?7)){3})/i", $line['agg'], $matches)) { if ($matches[0]) { $hostname = gethostbyaddr($line['agg']); } } if ($hostname !== false) { $hostnames[$line['agg']] = $hostname; $line['agg'] = $hostname; } } else { $line['agg'] = $hostnames[$line['agg']]; } } // Address resolution end if (! isset ($values['sources'][$line['agg']])) { continue; } $values['data'][$interval_start][$line['agg']] = $line['data']; } } } if (($aggregate != 'none') && (empty($values['data']))) { return array(); } return $values; } /** * Returns netflow stats for the given period in an array. * * @param string start_date Period start date. * @param string end_date Period end date. * @param string filter Netflow filter. * @param string aggregate Aggregate field. * @param int max Maximum number of aggregates. * @param string unit Unit to show. * * @return An array with netflow stats. */ function netflow_get_stats ($start_date, $end_date, $filter, $aggregate, $max, $unit, $connection_name = '', $address_resolution = false) { global $config, $nfdump_date_format; // Requesting remote data if (defined ('METACONSOLE') && $connection_name != '') { $data = metaconsole_call_remote_api ($connection_name, 'netflow_get_stats', "$start_date|$end_date|" . base64_encode(json_encode($filter)) . "|$aggregate|$max|$unit|" . (int)$address_resolution); return json_decode ($data, true); } // Get the command to call nfdump $command = netflow_get_command ($filter); // Execute nfdump $command .= " -o csv -q -n $max -s $aggregate/bytes -t " .date($nfdump_date_format, $start_date).'-'.date($nfdump_date_format, $end_date); exec($command, $string); if (! is_array($string)) { return array (); } // Remove the first line $string[0] = ''; $i = 0; $values = array(); $interval_length = $end_date - $start_date; foreach ($string as $line) { if ($line == '') { continue; } $val = explode(',',$line); $values[$i]['date'] = $val[0]; $values[$i]['time'] = $val[1]; //create field to sort array $datetime = $val[0]; $end_date = strtotime ($datetime); $values[$i]['datetime'] = $end_date; if ($aggregate == 'proto') { $values[$i]['agg'] = $val[3]; } else { // Address resolution start if ($address_resolution && ($aggregate == "srcip" || $aggregate == "dstip")) { global $hostnames; if (!isset($hostnames[$val[4]])) { $hostname = gethostbyaddr($val[4]); if ($hostname !== false) { $hostnames[$val[4]] = $hostname; $val[4] = $hostname; } } else { $val[4] = $hostnames[$val[4]]; } } // Address resolution end $values[$i]['agg'] = $val[4]; } if (! isset ($val[9])) { return array (); } switch ($unit){ case "megabytes": $values[$i]['data'] = $val[9] / 1048576; break; case "megabytespersecond": $values[$i]['data'] = $val[9] / 1048576 / $interval_length; break; case "kilobytes": $values[$i]['data'] = $val[9] / 1024; break; case "kilobytespersecond": $values[$i]['data'] = $val[9] / 1024 / $interval_length; break; default: case "bytes": $values[$i]['data'] = $val[9]; break; case "bytespersecond": $values[$i]['data'] = $val[9] / $interval_length; break; } $i++; } sort_netflow_data ($values); return $values; } /** * Returns a traffic summary for the given period in an array. * * @param string start_date Period start date. * @param string end_date Period end date. * @param string filter Netflow filter. * * @return An array with netflow stats. */ function netflow_get_summary ($start_date, $end_date, $filter, $connection_name = '') { global $nfdump_date_format; global $config; // Requesting remote data if (defined ('METACONSOLE') && $connection_name != '') { $data = metaconsole_call_remote_api ($connection_name, 'netflow_get_summary', "$start_date|$end_date|" . base64_encode(json_encode($filter))); return json_decode ($data, true); } // Get the command to call nfdump $command = netflow_get_command ($filter); // Execute nfdump $command .= " -o csv -n 1 -s srcip/bytes -t " .date($nfdump_date_format, $start_date).'-'.date($nfdump_date_format, $end_date); exec($command, $string); if (! is_array($string) || ! isset ($string[5])) { return array (); } // Read the summary $summary = explode (',', $string[5]); if (! isset ($summary[5])) { return array (); } $values['totalflows'] = $summary[0]; $values['totalbytes'] = $summary[1]; $values['totalpackets'] = $summary[2]; $values['avgbps'] = $summary[3]; $values['avgpps'] = $summary[4]; $values['avgbpp'] = $summary[5]; return $values; } /** * Returns a traffic record for the given period in an array. * * @param string start_date Period start date. * @param string end_date Period end date. * @param string filter Netflow filter. * @param int max Maximum number of elements. * @param string unit to show. * * @return An array with netflow stats. */ function netflow_get_record ($start_date, $end_date, $filter, $max, $unit, $address_resolution = false) { global $nfdump_date_format; global $config; // TIME_START = 0; // TIME_END = 1; // DURATION = 2; // SOURCE_ADDRESS = 3; // DESTINATION_ADDRESS = 4; // SOURCE_PORT = 5; // DESTINATION_PORT = 6; // PROTOCOL = 7; // INPUT_BYTES = 12; // Get the command to call nfdump $command = netflow_get_command($filter); // Execute nfdump $command .= " -q -o csv -n $max -s record/bytes -t " .date($nfdump_date_format, $start_date).'-'.date($nfdump_date_format, $end_date); exec($command, $result); if (! is_array($result)) { return array(); } $values = array(); foreach ($result as $key => $line) { $data = array(); $items = explode (',', $line); $data['time_start'] = $items[0]; $data['time_end'] = $items[1]; $data['duration'] = $items[2] / 1000; $data['source_address'] = $items[3]; $data['destination_address'] = $items[4]; $data['source_port'] = $items[5]; $data['destination_port'] = $items[6]; $data['protocol'] = $items[7]; switch ($unit){ case "megabytes": $data['data'] = $items[12] / 1048576; break; case "megabytespersecond": $data['data'] = $items[12] / 1048576 / $data['duration']; break; case "kilobytes": $data['data'] = $items[12] / 1024; break; case "kilobytespersecond": $data['data'] = $items[12] / 1024 / $data['duration']; break; default: case "bytes": $data['data'] = $items[12]; break; case "bytespersecond": $data['data'] = $items[12] / $data['duration']; break; } $values[] = $data; } // Address resolution start if ($address_resolution) { global $hostnames; for ($i = 0; $i < count($values); $i++) { if (!isset($hostnames[$values[$i]['source_address']])) { $hostname = gethostbyaddr($values[$i]['source_address']); if ($hostname !== false) { $hostnames[$values[$i]['source_address']] = $hostname; $values[$i]['source_address'] = $hostname; } } else { $values[$i]['source_address'] = $hostnames[$values[$i]['source_address']]; } if (!isset($hostnames[$values[$i]['destination_address']])) { $hostname = gethostbyaddr($values[$i]['destination_address']); if ($hostname !== false) { $hostnames[$values[$i]['destination_address']] = $hostname; $values[$i]['destination_address'] = $hostname; } } else { $values[$i]['destination_address'] = $hostnames[$values[$i]['destination_address']]; } } } // Address resolution end return $values; } /** * Returns the command needed to run nfdump for the given filter. * * @param array filter Netflow filter. * * @return Command to run. * */ function netflow_get_command ($filter) { global $config; // Build command $command = io_safe_output ($config['netflow_nfdump']) . ' -N'; // Netflow data path if (isset($config['netflow_path']) && $config['netflow_path'] != '') { $command .= ' -R. -M '.$config['netflow_path']; } // Filter options $command .= netflow_get_filter_arguments ($filter); return $command; } /** * Returns the nfdump command line arguments that match the given filter. * * @param array filter Netflow filter. * * @return Command line argument string. * */ function netflow_get_filter_arguments ($filter) { // Advanced filter $filter_args = ''; if ($filter['advanced_filter'] != '') { $filter_args = preg_replace('/["\r\n]/','', io_safe_output ($filter['advanced_filter'])); return ' "(' . $filter_args . ')"'; } // Normal filter if ($filter['ip_dst'] != '') { $filter_args .= ' "('; $val_ipdst = explode(',', io_safe_output ($filter['ip_dst'])); for($i = 0; $i < count ($val_ipdst); $i++){ if ($i > 0) { $filter_args .= ' or '; } if (netflow_is_net ($val_ipdst[$i]) == 0) { $filter_args .= 'dst ip '.$val_ipdst[$i]; } else { $filter_args .= 'dst net '.$val_ipdst[$i]; } } $filter_args .= ')'; } if ($filter['ip_src'] != '') { if ($filter_args == '') { $filter_args .= ' "('; } else { $filter_args .= ' and ('; } $val_ipsrc = explode(',', io_safe_output ($filter['ip_src'])); for ($i = 0; $i < count ($val_ipsrc); $i++) { if ($i > 0) { $filter_args .= ' or '; } if (netflow_is_net ($val_ipsrc[$i]) == 0) { $filter_args .= 'src ip '.$val_ipsrc[$i]; } else { $filter_args .= 'src net '.$val_ipsrc[$i]; } } $filter_args .= ')'; } if ($filter['dst_port'] != '') { if ($filter_args == '') { $filter_args .= ' "('; } else { $filter_args .= ' and ('; } $val_dstport = explode(',', io_safe_output ($filter['dst_port'])); for ($i = 0; $i < count ($val_dstport); $i++) { if ($i > 0) { $filter_args .= ' or '; } $filter_args .= 'dst port '.$val_dstport[$i]; } $filter_args .= ')'; } if ($filter['src_port'] != '') { if ($filter_args == '') { $filter_args .= ' "('; } else { $filter_args .= ' and ('; } $val_srcport = explode(',', io_safe_output ($filter['src_port'])); for ($i = 0; $i < count ($val_srcport); $i++) { if ($i > 0) { $filter_args .= ' or '; } $filter_args .= 'src port '.$val_srcport[$i]; } $filter_args .= ')'; } if (isset ($filter['proto']) && $filter['proto'] != '') { if ($filter_args == '') { $filter_args .= ' "('; } else { $filter_args .= ' and ('; } $val_proto = explode(',', io_safe_output ($filter['proto'])); for ($i = 0; $i < count ($val_proto); $i++) { if ($i > 0) { $filter_args .= ' or '; } $filter_args .= 'proto '.$val_proto[$i]; } $filter_args .= ')'; } if ($filter_args != '') { $filter_args .= '"'; } return $filter_args; } /** * Get the types of netflow charts. * * @return Array of types. * */ function netflow_get_chart_types () { return array( 'netflow_area' => __('Area graph'), 'netflow_pie_summatory' => __('Pie graph and Summary table'), 'netflow_statistics' => __('Statistics table'), 'netflow_data' => __('Data table'), 'netflow_mesh' => __('Circular mesh'), 'netflow_host_treemap' => __('Host detailed traffic')); } /** * Gets valid intervals for a netflow chart in the format: * * interval_length => interval_description * * @return Array of valid intervals. * */ function netflow_get_valid_intervals () { return array ( (string)SECONDS_10MINUTES => __('10 mins'), (string)SECONDS_15MINUTES => __('15 mins'), (string)SECONDS_30MINUTES => __('30 mins'), (string)SECONDS_1HOUR => __('1 hour'), (string)SECONDS_2HOUR => __('2 hours'), (string)SECONDS_5HOUR => __('5 hours'), (string)SECONDS_12HOURS => __('12 hours'), (string)SECONDS_1DAY => __('1 day'), (string)SECONDS_2DAY => __('2 days'), (string)SECONDS_5DAY => __('5 days'), (string)SECONDS_15DAYS => __('15 days'), (string)SECONDS_1WEEK => __('Last week'), (string)SECONDS_1MONTH => __('Last month'), (string)SECONDS_2MONTHS => __('2 months'), (string)SECONDS_3MONTHS => __('3 months'), (string)SECONDS_6MONTHS => __('6 months'), (string)SECONDS_1YEAR => __('Last year'), (string)SECONDS_2YEARS => __('2 years')); } /** * Gets valid intervals for a netflow chart in the format: * * interval_length => interval_description * * @return Array of valid intervals. * */ function netflow_get_valid_subintervals () { return array ( (string)SECONDS_1MINUTE => __('1 min'), (string)SECONDS_2MINUTES => __('2 mins'), (string)SECONDS_5MINUTES => __('5 mins'), (string)SECONDS_10MINUTES => __('10 mins'), (string)SECONDS_15MINUTES => __('15 mins'), (string)SECONDS_30MINUTES => __('30 mins'), (string)SECONDS_1HOUR => __('1 hour'), (string)SECONDS_2HOUR => __('2 hours'), (string)SECONDS_5HOUR => __('5 hours'), (string)SECONDS_12HOURS => __('12 hours'), (string)SECONDS_1DAY => __('1 day'), (string)SECONDS_2DAY => __('2 days'), (string)SECONDS_5DAY => __('5 days'), (string)SECONDS_15DAYS => __('15 days'), (string)SECONDS_1WEEK => __('1 week'), (string)SECONDS_1MONTH => __('1 month')); } /** * Draw a netflow report item. * * @param string start_date Period start date. * @param string end_date Period end date. * @param string interval_length Interval length in seconds (num_intervals * interval_length = start_date - end_date). * @param string type Chart type. * @param array filter Netflow filter. * @param int max_aggregates Maximum number of aggregates. * @param string output Output format. Only HTML and XML are supported. * * @return The netflow report in the appropriate format. */ function netflow_draw_item ($start_date, $end_date, $interval_length, $type, $filter, $max_aggregates, $connection_name = '', $output = 'HTML', $address_resolution = false) { $aggregate = $filter['aggregate']; $unit = $filter['output']; $interval = $end_date - $start_date; if (defined ('METACONSOLE')) { $width = 950; } else { $width = 850; } $height = 320; // Process item switch ($type) { case '0': case 'netflow_area': $data = netflow_get_data ($start_date, $end_date, $interval_length, $filter, $aggregate, $max_aggregates, $unit, $connection_name, $address_resolution); if (empty ($data)) { break; } if ($aggregate != 'none') { if ($output == 'HTML') { $html = "" . __('Unit') . ": " . netflow_format_unit ($unit); $html .= " " . __('Aggregate') . ": " . netflow_format_aggregate ($aggregate); if ($interval_length != 0) { $html .= " " . _('Resolution') . ": $interval_length " . __('seconds'); } $html .= graph_netflow_aggregate_area ($data, $interval, $width, $height, netflow_format_unit ($unit)); return $html; } else if ($output == 'PDF') { $html = "" . __('Unit') . ": " . netflow_format_unit ($unit); $html .= " " . __('Aggregate') . ": " . netflow_format_aggregate ($aggregate); if ($interval_length != 0) { $html .= " " . _('Resolution') . ": $interval_length " . __('seconds'); } $html .= graph_netflow_aggregate_area ($data, $interval, $width, $height, netflow_format_unit ($unit), 2, true); return $html; } else if ($output == 'XML') { $xml = "$unit\n"; $xml .= "$aggregate\n"; $xml .= "$interval_length\n"; $xml .= netflow_aggregate_area_xml ($data); return $xml; } } else { if ($output == 'HTML') { $html = "" . __('Unit') . ": " . netflow_format_unit ($unit); if ($interval_length != 0) { $html .= " " . _('Resolution') . ": $interval_length " . __('seconds'); } $html .= graph_netflow_total_area ($data, $interval, 660, 320, netflow_format_unit ($unit)); return $html; } else if ($output == 'PDF') { $html = "" . __('Unit') . ": " . netflow_format_unit ($unit); if ($interval_length != 0) { $html .= " " . _('Resolution') . ": $interval_length " . __('seconds'); } $html .= graph_netflow_total_area ($data, $interval, 660, 320, netflow_format_unit ($unit), 2, true); return $html; } else if ($output == 'XML') { $xml = "$unit\n"; $xml .= "$interval_length\n"; $xml .= netflow_total_area_xml ($data); return $xml; } } break; case '2': case 'netflow_data': $data = netflow_get_data ($start_date, $end_date, $interval_length, $filter, $aggregate, $max_aggregates, $unit, $connection_name, $address_resolution); if (empty ($data)) { break; } if ($output == 'HTML' || $output == 'PDF') { $html = "" . __('Unit') . ": " . netflow_format_unit ($unit); $html .= " " . __('Aggregate') . ": " . netflow_format_aggregate ($aggregate); if ($interval_length != 0) { $html .= " " . _('Resolution') . ": $interval_length " . __('seconds'); } $html .= "
"; $html .= netflow_data_table ($data, $start_date, $end_date, $aggregate, $unit); $html .= "
"; return $html; } else if ($output == 'XML') { $xml = "$unit\n"; $xml .= "$aggregate\n"; $xml .= "$interval_length\n"; // Same as netflow_aggregate_area_xml $xml .= netflow_aggregate_area_xml ($data); return $xml; } break; case '3': case 'netflow_statistics': $data = netflow_get_stats ($start_date, $end_date, $filter, $aggregate, $max_aggregates, $unit, $connection_name, $address_resolution); if (empty ($data)) { break; } if ($output == 'HTML' || $output == 'PDF') { $html = netflow_stat_table ($data, $start_date, $end_date, $aggregate, $unit); return $html; } else if ($output == 'XML') { return netflow_stat_xml ($data); } break; case '4': case 'netflow_summary': $data_summary = netflow_get_summary ($start_date, $end_date, $filter, $connection_name); if (empty ($data_summary)) { break; } if ($output == 'HTML' || $output == 'PDF') { return netflow_summary_table ($data_summary); } else if ($output == 'XML') { return netflow_summary_xml ($data_summary); } break; case '1': case 'netflow_pie': $data_pie = netflow_get_stats ($start_date, $end_date, $filter, $aggregate, $max_aggregates, $unit, $connection_name, $address_resolution); if (empty ($data_pie)) { break; } if ($output == 'HTML') { $html = "" . __('Unit') . ": " . netflow_format_unit ($unit); $html .= " " . __('Aggregate') . ": " . netflow_format_aggregate ($aggregate); $html .= graph_netflow_aggregate_pie ($data_pie, netflow_format_aggregate ($aggregate)); return $html; } else if ($output == 'PDF') { $html = "" . __('Unit') . ": " . netflow_format_unit ($unit); $html .= " " . __('Aggregate') . ": $aggregate"; $html .= graph_netflow_aggregate_pie ($data_pie, netflow_format_aggregate ($aggregate), 2, true); return $html; } else if ($output == 'XML') { $xml = "$unit\n"; $xml .= "$aggregate\n"; $xml .= netflow_aggregate_pie_xml ($data_pie); return $xml; } break; case 'netflow_pie_summatory': $data_summary = netflow_get_summary ($start_date, $end_date, $filter, $connection_name); if (empty ($data_summary)) { break; } $data_pie = netflow_get_stats ($start_date, $end_date, $filter, $aggregate, $max_aggregates, $unit, $connection_name, $address_resolution); if (empty ($data_pie)) { break; } switch ($output) { case 'HTML': $html = ''; $html .= ''; $html .= ''; $html .= ''; $html .= ''; $html .= '
'; $html .= netflow_summary_table ($data_summary); $html .= "" . __('Unit') . ": " . netflow_format_unit ($unit); $html .= " " . __('Aggregate') . ": " . netflow_format_aggregate ($aggregate); $html .= ''; $html .= graph_netflow_aggregate_pie ($data_pie, netflow_format_aggregate ($aggregate)); $html .= '
'; return $html; break; case 'PDF': break; case 'XML': return netflow_summary_xml ($data_summary); break; } break; case 'netflow_mesh': $netflow_data = netflow_get_record($start_date, $end_date, $filter, $max_aggregates, $unit, $address_resolution); switch ($aggregate) { case "srcport": case "dstport": $source_type = "source_port"; $destination_type = "destination_port"; break; default: case "dstip": case "srcip": $source_type = "source_address"; $destination_type = "destination_address"; break; } $data = array(); $data['elements'] = array(); $data['matrix'] = array(); foreach ($netflow_data as $record) { if (!in_array($record[$source_type], $data['elements'])) { $data['elements'][] = $record[$source_type]; $data['matrix'][] = array(); } if (!in_array($record[$destination_type], $data['elements'])) { $data['elements'][] = $record[$destination_type]; $data['matrix'][] = array(); } } for ($i = 0; $i < count($data['matrix']); $i++) { $data['matrix'][$i] = array_fill(0, count($data['matrix']), 0); } foreach ($netflow_data as $record) { $source_key = array_search($record[$source_type], $data['elements']); $destination_key = array_search($record[$destination_type], $data['elements']); if ($source_key !== false && $destination_key !== false) { $data['matrix'][$source_key][$destination_key] += $record['data']; } } $html = "
"; $html .= graph_netflow_circular_mesh ($data, netflow_format_unit($unit), 700); $html .= "
"; return $html; break; case 'netflow_host_treemap': $netflow_data = netflow_get_record($start_date, $end_date, $filter, $max_aggregates, $unit, $address_resolution); switch ($aggregate) { case "srcip": case "srcport": $address_type = "source_address"; $port_type = "source_port"; $type = __("Sent"); break; default: case "dstip": case "dstport": $address_type = "destination_address"; $port_type = "destination_port"; $type = __("Received"); break; } $data_aux = array(); foreach ($netflow_data as $record) { $address = $record[$address_type]; $port = $record[$port_type]; if (!isset($data_aux[$address])) $data_aux[$address] = array(); if (!isset($data_aux[$address][$port])) $data_aux[$address][$port] = 0; $data_aux[$address][$port] += $record['data']; } $id = -1; $data = array(); if (! empty($netflow_data)) { $data['name'] = __("Host detailed traffic") . ": " . $type; $data['children'] = array(); foreach ($data_aux as $address => $ports) { $children = array(); $children['id'] = $id++; $children['name'] = $address; $children['children'] = array(); foreach ($ports as $port => $value) { $children_data = array(); $children_data['id'] = $id++; $children_data['name'] = $port; $children_data['value'] = $value; $children_data['tooltip_content'] = "$port: " . format_numeric($value) . " " . netflow_format_unit($unit) . ""; $children['children'][] = $children_data; } $data['children'][] = $children; } } return graph_netflow_host_traffic ($data, netflow_format_unit($unit), 'auto', 400); break; default: break; } if ($output == 'HTML' || $output == 'PDF') { return graph_nodata_image(300, 110, 'data'); } } /** * Render a netflow report as an XML. * * @param int ID of the netflow report. * @param string end_date Period start date. * @param string end_date Period end date. * @param string interval_length Interval length in seconds (num_intervals * interval_length = start_date - end_date). * */ function netflow_xml_report ($id, $start_date, $end_date, $interval_length = 0) { // Get report data $report = db_get_row_sql ('SELECT * FROM tnetflow_report WHERE id_report =' . (int) $id); if ($report === FALSE) { echo "" . __('Error generating report') . "\n"; return; } // Print report header $time = get_system_time (); echo ''; echo "\n"; echo " \n"; echo " " . $time . "\n"; echo " " . date ("r", $time) . "\n"; echo " \n"; echo " " . io_safe_output ($report['id_name']) . "\n"; echo " " . io_safe_output ($report['description']) . "\n"; echo " " . date ("r", $start_date) . "\n"; echo " " . date ("r", $end_date) . "\n"; // Get netflow item types $item_types = netflow_get_chart_types (); // Print report items $report_contents = db_get_all_rows_sql ("SELECT * FROM tnetflow_report_content WHERE id_report='" . $report['id_report'] . "' ORDER BY `order`"); foreach ($report_contents as $content) { // Get item filters $filter = db_get_row_sql("SELECT * FROM tnetflow_filter WHERE id_sg = '" . io_safe_input ($content['id_filter']) . "'", false, true); if ($filter === FALSE) { continue; } echo " \n"; echo " " . io_safe_output ($content['description']) . "\n"; echo " " . io_safe_output ($item_types[$content['show_graph']]) . "\n"; echo " " . $content['max'] . "\n"; echo " \n"; echo " " . io_safe_output ($filter['id_name']) . "\n"; echo " " . io_safe_output ($filter['ip_src']) . "\n"; echo " " . io_safe_output ($filter['ip_dst']) . "\n"; echo " " . io_safe_output ($filter['src_port']) . "\n"; echo " " . io_safe_output ($filter['src_port']) . "\n"; echo " " . io_safe_output ($filter['advanced_filter']) . "\n"; echo " " . io_safe_output ($filter['aggregate']) . "\n"; echo " " . io_safe_output ($filter['output']) . "\n"; echo " \n"; echo netflow_draw_item ($start_date, $end_date, $interval_length, $content['show_graph'], $filter, $content['max'], $report['server_name'], 'XML'); echo " \n"; } echo "\n"; } /** * Render an aggregated area chart as an XML. * * @param array Netflow data. * */ function netflow_aggregate_area_xml ($data) { // Print source information if (isset($data['sources'])) { echo "\n"; foreach ($data['sources'] as $source => $discard) { echo "$source\n"; } echo "\n"; // Print flow information echo "\n"; foreach ($data['data'] as $timestamp => $flow) { echo "\n"; echo " " . $timestamp . "\n"; echo " \n"; foreach ($flow as $source => $data) { echo " $source\n"; echo " " . $data . "\n"; } echo " \n"; echo "\n"; } echo "\n"; } else { echo "\n"; foreach ($data as $timestamp => $flow) { echo "\n"; echo " " . $timestamp . "\n"; echo " " . $flow['data'] . "\n"; echo "\n"; } echo "\n"; } } /** * Render an area chart as an XML. * * @param array Netflow data. * */ function netflow_total_area_xml ($data) { // Print flow information $xml = "\n"; foreach ($data as $timestamp => $flow) { $xml .= "\n"; $xml .= " " . $timestamp . "\n"; $xml .= " " . $flow['data'] . "\n"; $xml .= "\n"; } $xml .= "\n"; return $xml; } /** * Render a pie chart as an XML. * * @param array Netflow data. * */ function netflow_aggregate_pie_xml ($data) { // Calculate total $total = 0; foreach ($data as $flow) { $total += $flow['data']; } if ($total == 0) { return; } // Print percentages echo "\n"; foreach ($data as $flow) { echo "" . $flow['agg'] . "\n"; echo "" . format_numeric (100 * $flow['data'] / $total, 2) . "%\n"; } echo "\n"; } /** * Render a stats table as an XML. * * @param array Netflow data. * */ function netflow_stat_xml ($data) { // Print stats $xml .= "\n"; foreach ($data as $flow) { $xml .= "" . $flow['agg'] . "\n"; $xml .= "" . $flow['data'] . "\n"; } $xml .= "\n"; return $xml; } /** * Render a summary table as an XML. * * @param array Netflow data. * */ function netflow_summary_xml ($data) { // Print summary $xml = "\n"; $xml .= " " . $data['totalflows'] . "\n"; $xml .= " " . $data['totalbytes'] . "\n"; $xml .= " " . $data['totalbytes'] . "\n"; $xml .= " " . $data['avgbps'] . "\n"; $xml .= " " . $data['avgpps'] . "\n"; $xml .= " " . $data['avgpps'] . "\n"; $xml .= "\n"; return $xml; } /** * Return a string describing the given unit. * * @param string Netflow unit. */ function netflow_format_unit ($unit) { switch ($unit){ case 'megabytes': return __('MB'); case 'megabytespersecond': return __('MB/s'); case 'kilobytes': return __('kB'); case 'kilobytespersecond': return __('kB/s'); case 'bytes': return __('Bytes'); case 'bytespersecond': return __('B/s'); default: return ''; } } /** * Return a string describing the given aggregate. * * @param string Netflow aggregate. */ function netflow_format_aggregate ($aggregate) { switch ($aggregate){ case 'dstport': return __('Dst port'); case 'dstip': return __('Dst IP'); case 'proto': return __('Protocol'); case 'srcip': return __('Src IP'); case 'srcport': return __('Src port'); default: return ''; } } /** * Check the nfdump binary for compatibility. * * @param string nfdump binary full path. * * @return 1 if the binary does not exist or is not executable, 2 if a * version older than 1.6.8 is installed or the version cannot be * determined, 0 otherwise. */ function netflow_check_nfdump_binary ($nfdump_binary) { // Check that the binary exists and is executable if (! is_executable ($nfdump_binary)) { return 1; } // Check at least version 1.6.8 $output = ''; $rc = -1; exec ($nfdump_binary . ' -V', $output, $rc); if ($rc != 0) { return 2; } $matches = array(); foreach ($output as $line) { if (preg_match ('/Version:[^\d]+(\d+)\.(\d+)\.(\d+)/', $line, $matches) === 1) { if ($matches[1] < 1) { return 2; } if ($matches[2] < 6) { return 2; } if ($matches[3] < 8) { return 2; } return 0; } } return 2; } ?>