#! /usr/bin/perl # # Purpose: # FlowTracker_Grapher runs periodically (configurable) to update FlowTracker # graphs with the latest data collected by FlowTracker_Collector. # # Description: # The user initiates the script from a command line appending an "&" to put # it in the background. The script re-creates four graphs for each existing # RRDtool file (i.e., last 24 hours, last 7 days, last month, last year.) # A set of rrdtool parameters, in the FlowViewer_Configuration.pm file, # permits the user to configure parameters like size and color, etc.. When # finished with all of the existing Trackings, the script will go to sleep for # the remainder of the specified graphing period. # # Controlling Parameters (specified in FlowViewer_Configuration.pm): # Name Description # ----------------------------------------------------------------------- # rrd_area Color of the area underneath the graph # rrd_line Color of the line at the top of the graphed area # rrd_width Width of the graph # rrd_height Height of the graph # rrd_font Color of the font used in the graphs # rrd_back Image background color # rrd_canvas Color of the background of the actual graph # rrd_grid Color of the minor grid lines # rrd_mgrid Color of the major grid lines # rrd_frame Color of the graph frame # rrd_shadea Color for the top and left border # rrd_shadeb Color for the right and bottom border # rrd_thick Thickness of the line at the top of the graph # rrd_lower_limit Bottom of the y-axis # rrd_slope_mode "--slope-mode" will round off tops of graph # rrd_vrule_color Color of the line that indicates when the filter was changed # # Modification history: # Author Date Vers. Description # ----------------------------------------------------------------------- # J. Loiacono 07/04/2006 3.0 Original version. # J. Loiacono 12/25/2006 3.1 Archives, lazy-mode, permissions # J. Loiacono 02/14/2007 3.2 Changes to incorporate Groups # #$Author$ #$Date$ #$Header$ # ########################################################################### # # BEGIN EXECUTABLE STATEMENTS # use FlowViewer_Configuration; use FlowViewer_Utilities; use lib $cgi_bin_directory; # Load the colors $colors_file = "$cgi_bin_directory/FlowGrapher_Colors"; open (COLORS,"<$colors_file") || die "Can't open colors file; $colors_file\n"; while () { chop; ($red,$green,$blue,$color_1,$color_2) = split(/\s+/); $color_name = $color_1; if ($color_2 ne "") { $color_name = $color_1 . " " . $color_2; } $R = &dec2hex($red); if (length($R) < 2) { $R = "0" . $R; } $G = &dec2hex($green); if (length($G) < 2) { $G = "0" . $G; } $B = &dec2hex($blue); if (length($B) < 2) { $B = "0" . $B; } $hex_colors{$color_name} = $R . $G . $B; } $hex_colors{"standard"} = $rrd_area; sub dec2hex($) { return sprintf("%lx", $_[0]) } $a = 0; while ($a == 0) { if ($log_grapher eq "Y") { open (LOG,">>$log_directory/FlowTracker_Grapher.log"); } if ($debug_tracker eq "Y") { open(DEBUG,">$work_directory/DEBUG_TRACKER"); } $end_rrd = time; $num_trackings = 0; $groups_exist = 0; $archives_exist = 0; %trackings = (); if (($log_grapher eq "Y") || (debug_grapher eq "Y")) { $current_time = time; $current_time_out = epoch_to_date($current_time,"LOCAL"); $current_time_rrd = $current_time_out; $current_time_rrd =~ s/:/\\:/g; if ($log_grapher eq "Y") { print LOG "Starting a graphing loop at: $current_time_out\n"; } if ($debug_tracker eq "Y") { print DEBUG "Starting a graphing loop at: $current_time_out\n"; } } # Work through each tracking while ($filter_file = <$filter_directory/*>) { ($directory,$tracking) = $filter_file =~ m/(.*\/)(.*)$/; ($tracking,$extension) = split(/\./,$tracking); $num_trackings++; # Load information from filter file for graph and HTML page re-creation %FORM = (); $tracking_type = ""; @component_links = (); $vrule_1 = ""; $vrule_2 = ""; $vrule_3 = ""; $call_string = ""; open (FILTER,"<$filter_file"); while () { chop; $key = substr($_,0,8); if ($key eq " input: ") { ($input,$field,$field_value) = split(/: /); if ($field eq "tracking_type") { $tracking_type = $field_value; } if ($field eq "tracking_label") { $FORM{tracking_label} = $field_value; $trackings{$tracking} = $field_value; $tracking_label = $field_value; } if ($field eq "general_comment") { $FORM{general_comment} = $field_value; $general_comment = $field_value; } if ($field eq "device_name") { $FORM{device_name} = $field_value; $call_string = "device_name=$field_value&"; } if ($field eq "source_addresses") { $FORM{source_address} = $field_value; $call_string .= "source_addresses=$field_value&"; } if ($field eq "source_ports") { $FORM{source_port} = $field_value; $call_string .= "source_ports=$field_value&"; } if ($field eq "source_ifs") { $FORM{source_if} = $field_value; $call_string .= "source_ifs=$field_value&"; } if ($field eq "source_ases") { $FORM{source_as} = $field_value; $call_string .= "source_ases=$field_value&"; } if ($field eq "dest_addresses") { $FORM{dest_address} = $field_value; $call_string .= "dest_addresses=$field_value&"; } if ($field eq "dest_ports") { $FORM{dest_port} = $field_value; $call_string .= "dest_ports=$field_value&"; } if ($field eq "dest_ifs") { $FORM{dest_if} = $field_value; $call_string .= "dest_ifs=$field_value&"; } if ($field eq "dest_ases") { $FORM{dest_as} = $field_value; $call_string .= "dest_ases=$field_value&"; } if ($field eq "protocols") { $FORM{protocols} = $field_value; $call_string .= "protocols=$field_value&"; } if ($field eq "tos_fields") { $FORM{tos_fields} = $field_value; $call_string .= "tcp_flags=$field_value&"; } if ($field eq "tcp_flags") { $FORM{tcp_flags} = $field_value; $call_string .= "tos_fields=$field_value&"; } if ($field eq "revision") { ($notate_graphs,$revision_date,$revision_comment) = split(/\|/,$field_value); $revision_date_out = epoch_to_date($revision_date,"LOCAL"); $revision_date_out =~ s/:/\\:/g; if ($notate_graphs eq "Y") { if ($vrule_1 eq "") { $vrule_1 = " VRULE:$revision_date#$rrd_vrule_color:\"$revision_date_out\\: $revision_comment\\n\""; next; } elsif ($vrule_2 eq "") { $vrule_2 = " VRULE:$revision_date#$rrd_vrule_color:\"$revision_date_out\\: $revision_comment\\n\""; next; } elsif ($vrule_3 eq "") { $vrule_3 = " VRULE:$revision_date#$rrd_vrule_color:\"$revision_date_out\\: $revision_comment\\n\""; next; } } } } else { } } close (FILTER); $call_string =~ s/\s+//g; $trackings{$tracking} .= "^" . $general_comment; if ($tracking_type eq "Group") { open (FILTER,"<$filter_file"); while () { chop; $key = substr($_,0,8); if ($key eq " input: ") { next; } else { ($component_position,$component_label,$component_color) = split(/\^/); $component_file = $component_label; $component_file =~ s/^\s+//; $component_file =~ s/\s+$//; $component_file =~ s/\&/-/g; $component_file =~ s/\//-/g; $component_file =~ s/\(/-/g; $component_file =~ s/\)/-/g; $component_file =~ s/\./-/g; $component_file =~ s/\s+/_/g; $component_file =~ tr/[A-Z]/[a-z]/; $component_html = $tracker_short ."/". $component_file ."/index.html"; push (@component_links,$component_html); } } } $html_directory = $tracker_directory ."/". $tracking; $html_file = $html_directory ."/index.html"; $tracking_file = $tracking; &create_FlowTracker_html; # Look to skip Archives if ($extension eq "archive") { $trackings{$tracking} .= "^Archive"; $archives_exist = 1; next; } elsif ($tracking_type eq "Group") { $trackings{$tracking} .= "^Group"; $groups_exist = 1; } if ($log_grapher) { print LOG "creating graphs for: $tracking\n"; } # Create each of the four graphs for this tracking $rrdtool_file = "$rrdtool_directory/$tracking" . ".rrd"; foreach $graph_type ("Daily", "Weekly", "Monthly", "Yearly") { if ($graph_type eq "Daily") { $start_rrd = $end_rrd - 86400; $line_peak = "", $sample = " Data collected over 5 minute periods Graph Last Updated\\: $current_time_rrd"; $rrd_title = "\"Last 24 Hours\""; $graph_file = "$tracker_directory/$tracking/daily.png"; } elsif ($graph_type eq "Weekly") { $start_rrd = $end_rrd - (7*86400); $line_peak = "LINE$rrd_thick:flowpeak#$rrd_peak:\"Peak 5 Minute Period\"", $sample = " Data averaged over 30 minute periods Graph Last Updated\\: $current_time_rrd"; $rrd_title = "\"Last 7 Days\""; $graph_file = "$tracker_directory/$tracking/weekly.png"; } elsif ($graph_type eq "Monthly") { $start_rrd = $end_rrd - (28*86400); $line_peak = "LINE$rrd_thick:flowpeak#$rrd_peak:\"Peak 5 Minute Period\"", $sample = " Data averaged over 2 hour periods Graph Last Updated\\: $current_time_rrd"; $rrd_title = "\"Last 4 Weeks\""; $graph_file = "$tracker_directory/$tracking/monthly.png"; } elsif ($graph_type eq "Yearly") { $start_rrd = $end_rrd - (365*86400); $line_peak = "LINE$rrd_thick:flowpeak#$rrd_peak:\"Peak 5 Minute Period\"", $sample = " Data averaged over 24 hour periods Graph Last Updated\\: $current_time_rrd"; $rrd_title = "\"Last 12 Months\""; $graph_file = "$tracker_directory/$tracking/yearly.png"; } if ($extension eq "grp") { $DEF_parameters = ""; $AREA_parameters = ""; @components = (); open (GROUP,"<$filter_file"); @group_lines = ; close (GROUP); foreach $group_line (@group_lines) { if ($group_line =~ / input:/) { next; } else { push (@components,$group_line); } } $num_components = 0; $first_below = 1; foreach $component (@components) { $num_components++; chop $component; ($component_position,$component_label,$component_color) = split(/\^/,$component); $component_file = $component_label; $component_file =~ s/^\s+//; $component_file =~ s/\s+$//; $component_file =~ s/\&/-/g; $component_file =~ s/\//-/g; $component_file =~ s/\(/-/g; $component_file =~ s/\)/-/g; $component_file =~ s/\./-/g; $component_file =~ s/\s+/_/g; $component_file =~ tr/[A-Z]/[a-z]/; $component_rrd = $rrdtool_directory ."/". $component_file .".rrd"; $DEF_parameters .= "DEF:flowbits$num_components=$component_rrd:flowbits:AVERAGE "; $AREA_parameters .= "COMMENT:\" \" "; if ($component_position < 200) { $AREA_parameters .= "AREA:flowbits$num_components#$hex_colors{$component_color}:\"$component_label\\n\":STACK "; } elsif (($component_position >= 200) && ($first_below)) { $DEF_parameters .= "CDEF:flowbits_below$num_components=flowbits$num_components,-1,* "; $AREA_parameters .= "AREA:flowbits_below$num_components#$hex_colors{$component_color}:\"$component_label\\n\" "; $first_below = 0; } else { $DEF_parameters .= "CDEF:flowbits_below$num_components=flowbits$num_components,-1,* "; $AREA_parameters .= "AREA:flowbits_below$num_components#$hex_colors{$component_color}:\"$component_label\\n\":STACK "; } } @graph_parameters = ('--title',"$rrd_title", '--start',$start_rrd, '--end',$end_rrd, '--width',$rrd_width, '--height',$rrd_height, '--interlace', '--lazy', '--vertical-label',"\"Bits per Second\"", $rrd_slope_mode, "--color=FONT#$rrd_font", "--color=BACK#$rrd_back", "--color=CANVAS#$rrd_canvas", "--color=GRID#$rrd_grid", "--color=MGRID#$rrd_mgrid", "--color=FRAME#$rrd_frame", "--color=SHADEA#$rrd_frame", "--color=SHADEB#$rrd_frame", '--lower-limit',$rrd_lower_limit, '--alt-autoscale', $DEF_parameters, "COMMENT:\"$sample \"", "COMMENT:\"\\n\"", $AREA_parameters); } else { @graph_parameters = ('--title',"$rrd_title", '--start',$start_rrd, '--end',$end_rrd, '--width',$rrd_width, '--height',$rrd_height, '--interlace', '--lazy', '--vertical-label',"\"Bits per Second\"", $rrd_slope_mode, "--color=FONT#$rrd_font", "--color=BACK#$rrd_back", "--color=CANVAS#$rrd_canvas", "--color=GRID#$rrd_grid", "--color=MGRID#$rrd_mgrid", "--color=FRAME#$rrd_frame", "--color=SHADEA#$rrd_frame", "--color=SHADEB#$rrd_frame", '--lower-limit',$rrd_lower_limit, "DEF:flowbits=$rrdtool_file:flowbits:AVERAGE", "DEF:flowpeak=$rrdtool_file:flowbits:MAX", 'VDEF:flowbitsmax=flowbits,MAXIMUM', 'VDEF:flowbitsavg=flowbits,AVERAGE', 'VDEF:flowbitsmin=flowbits,MINIMUM', 'VDEF:flowbitspct=flowbits,95,PERCENT', "AREA:flowbits#$rrd_area", "LINE$rrd_thick:flowbits#$rrd_line:", "COMMENT:\"$sample \"", "COMMENT:\"\\n\"", "COMMENT:\" 95th percentile \"", "GPRINT:flowbitspct:\"%6.2lf %Sbps\"", "COMMENT:\" \"", $line_peak, "COMMENT:\"\\n\"", "COMMENT:\" Maximum \"", "GPRINT:flowbitsmax:\"%6.2lf %Sbps \"", "COMMENT:\"\\n\"", "COMMENT:\" Average \"", "GPRINT:flowbitsavg:\"%6.2lf %Sbps \"", "COMMENT:\"\\n\"", "COMMENT:\" Minimum \"", "GPRINT:flowbitsmin:\"%6.2lf %Sbps \"", "COMMENT:\"\\n\"", "COMMENT:\"\\n\"", "COMMENT:\" \"", $vrule_1, "COMMENT:\" \"", $vrule_2, "COMMENT:\" \"", $vrule_3); } $rrdgraph_command = "$rrdtool_bin_directory/rrdtool graph " . "$graph_file " . "@graph_parameters " . ">/dev/null"; system($rrdgraph_command); chmod $graph_file_perms, $graph_file; if ($debug_tracker eq "Y") { print DEBUG "finished $graph_type for $graph_file\n"; } } } # Update the Active Trackings HTML file $active_trackings_webpage = "$tracker_directory/$actives_webpage"; open(TRACKINGS,">$active_trackings_webpage"); print TRACKINGS "\n"; print TRACKINGS "\n"; print TRACKINGS "\n"; print TRACKINGS "FlowTracker Active Trackings\n"; print TRACKINGS "\n"; print TRACKINGS "\n"; print TRACKINGS "\n"; print TRACKINGS ""; print TRACKINGS "
\n"; print TRACKINGS ""; print TRACKINGS "\n"; print TRACKINGS "\n"; print TRACKINGS "\n"; print TRACKINGS "\n"; print TRACKINGS "\n"; print TRACKINGS "
\n"; print TRACKINGS "\n"; print TRACKINGS "\n"; print TRACKINGS "

$trackings_title\n"; print TRACKINGS "
Netflow Trackings

\n"; print TRACKINGS "
\n"; print TRACKINGS "

\n"; print TRACKINGS ""; print TRACKINGS "\n"; @sorted_trackings = sort (keys (%trackings)); # Output the Individual Trackings print TRACKINGS "\n"; print TRACKINGS "\n"; foreach $tracking (@sorted_trackings) { ($tracking_label,$general_comment,$class) = split(/\^/,$trackings{$tracking}); if ($class ne "") { next; } if ($debug_tracker eq "Y") { print DEBUG "active tracking: $tracking\n"; } $tracking_link = "$tracking_label"; print TRACKINGS "\n"; print TRACKINGS "\n"; print TRACKINGS "\n"; print TRACKINGS "\n"; } # Output the Group Trackings if ($groups_exist) { print TRACKINGS "\n"; print TRACKINGS "\n"; foreach $tracking (@sorted_trackings) { ($tracking_label,$general_comment,$class) = split(/\^/,$trackings{$tracking}); if ($class ne "Group") { next; } if ($debug_tracker eq "Y") { print DEBUG "group tracking: $tracking\n"; } $tracking_link = "$tracking_label"; print TRACKINGS "\n"; print TRACKINGS "\n"; print TRACKINGS "\n"; print TRACKINGS "\n"; } } # Output the Archived Trackings if ($archives_exist) { print TRACKINGS "\n"; print TRACKINGS "\n"; foreach $tracking (@sorted_trackings) { ($tracking_label,$general_comment,$class) = split(/\^/,$trackings{$tracking}); if ($class ne "Archive") { next; } if ($debug_tracker eq "Y") { print DEBUG "archived tracking: $tracking\n"; } $tracking_link = "$tracking_label"; print TRACKINGS "\n"; print TRACKINGS "\n"; print TRACKINGS "\n"; print TRACKINGS "\n"; } } print TRACKINGS "
Individual TrackingsGeneral Comment
\n"; print TRACKINGS ""; print TRACKINGS "$tracking_link"; print TRACKINGS "\n"; print TRACKINGS ""; print TRACKINGS "$general_comment
"; print TRACKINGS "
Group TrackingsGeneral Comment
\n"; print TRACKINGS ""; print TRACKINGS "$tracking_link"; print TRACKINGS "\n"; print TRACKINGS ""; print TRACKINGS "$general_comment
"; print TRACKINGS "
Archived TrackingsGeneral Comment
\n"; print TRACKINGS ""; print TRACKINGS "$tracking_link"; print TRACKINGS "\n"; print TRACKINGS ""; print TRACKINGS "$general_comment
"; print TRACKINGS "
\n"; print TRACKINGS "\n"; print TRACKINGS "\n"; close(TRACKINGS); chmod $actives_file_perms, $active_trackings_webpage; # Update log and go to sleep for what remains of 5-minute period $end_graphing_time = time; $loop_time = $end_graphing_time - $end_rrd; $sleep_period = $graphing_period - $loop_time; if ($log_grapher eq "Y") { print LOG "Finished with this loop. $num_trackings graph sets created. Loop took: $loop_time seconds sleep_period: $sleep_period\n\n"; } close (LOG); close (DEBUG); sleep ($sleep_period); }