pandorafms/pandora_server/lib/PandoraFMS/Goliat/GoliatCURL.pm

369 lines
10 KiB
Perl
Executable File

##################################################################################
# Goliath Tools CURL Module
##################################################################################
# Copyright (c) 2013-2023 Pandora FMS
# This code is not free or OpenSource. Please don't redistribute.
##################################################################################
package PandoraFMS::Goliat::GoliatCURL;
use PandoraFMS::Goliat::GoliatTools;
use strict;
use warnings;
use Data::Dumper;
use PandoraFMS::DB;
use IO::Socket::INET6;
use URI::Escape;
use Time::Local;
use Time::HiRes qw ( gettimeofday );
# Japanese encoding support
use Encode::Guess qw/euc-jp shiftjis iso-2022-jp/;
require Exporter;
our @ISA = ("Exporter");
our %EXPORT_TAGS = ( 'all' => [ qw() ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw(
g_http_task
@task_requests
@task_reqsec
@task_fails
@task_time
@task_end
@task_sessions
@task_ssec
@task_get_string
@task_get_content
@task_session_fails
);
our @task_requests;
our @task_reqsec;
our @task_fails ;
our @task_time;
our @task_end;
our @task_sessions;
our @task_ssec;
our @task_get_string;
our @task_get_content;
our @task_session_fails;
our $goliat_abort;
# Returns a string than can be safely used as a command line parameter for CURL
sub safe_param ($) {
my $string = shift;
$string =~ s/'/"/g;
return "'" . $string . "'";
}
sub g_http_task {
my ( $config, $thread_id, @work_list ) = @_;
my ( $ax, $bx, $cx ); # used in FOR loop
my ( $ttime1, $ttime2, $ttime_tot );
my $resp; # HTTP Response
my $total_requests = 0;
my $total_valid_requests = 0;
my $total_invalid_request = 0;
my $cookie_file = "/tmp/gtc_".$thread_id."_".g_trash_ascii (3);
my $check_string = 1;
my $get_string = "";
my $get_content = "";
my $get_content_advanced = "";
my $timeout = 10;
#my $ua = new LWP::UserAgent;
$task_requests [$thread_id] = 0 ;
$task_sessions [$thread_id] = 0 ;
$task_reqsec[$thread_id] = 0;
$task_fails[$thread_id] = 0;
$task_session_fails[$thread_id] = 0;
$task_ssec[$thread_id] = 0;
$task_end[$thread_id] = 0;
$task_time[$thread_id] = 0;
$task_get_string[$thread_id] = "";
$task_get_content[$thread_id] = "";
# Set command line options for CURL
my $curl_opts;
# Follow redirects
$curl_opts .= " --location-trusted";
# User agent
if ($config->{"agent"} ne '') {
$curl_opts .= " -A " . safe_param($config->{"agent"})
}
# Prevent pages from being cached
$curl_opts .= " -H 'Pragma: no-cache'";
# Timeout
if (defined ($config->{"timeout"}) && $config->{"timeout"} > 0) {
$timeout = $config->{"timeout"};
}
# Maximum file size
if (defined($config->{"maxsize"}) && $config->{"maxsize"} > 0) {
$curl_opts .= " --max-filesize " . $config->{"maxsize"};
}
# Disable SSL certificate host verification
$curl_opts .= " -k";
# Proxy
if ($config->{'proxy'} ne ""){
$curl_opts .= " -x " . safe_param($config->{'proxy'});
}
# Proxy HTTP authentication
if ($config->{'auth_user'} ne "") {
$curl_opts .= " --proxy-anyauth -U " . safe_param($config->{'auth_user'} . ':' . $config->{'auth_pass'});
}
# Delete existing cookies
my $cookie_carry_on = 0;
if ( -e $cookie_file){
unlink ($cookie_file);
}
$ttime1 = Time::HiRes::gettimeofday();
for ($ax = 0; $ax != $config->{'retries'}; $ax++){
for ($bx = 0; $bx < $config->{"work_items"}; $bx++){
if ($config->{'con_delay'} > 0){
sleep ($config->{'con_delay'});
}
$total_requests++;
# Start to count!
$check_string = 1;
# Prepare parameters
my $task_curl_opts = $curl_opts;
my $params = "";
$cx = 0;
while (defined($work_list[$bx]->{'variable_name'}[$cx])){
if ($cx > 0){
$params = $params."&";
}
$params = $params . $work_list[$bx]->{'variable_name'}[$cx] . "=" . uri_escape($work_list[$bx]->{'variable_value'}[$cx]);
$cx++;
}
# Cookie carry on
if (defined ($work_list[$bx]->{'cookie'}) && $work_list[$bx]->{'cookie'} == 1){
$cookie_carry_on = 1;
}
if ($cookie_carry_on == 1) {
$task_curl_opts .= " -c " . safe_param ($cookie_file);
$task_curl_opts .= " -b " . safe_param ($cookie_file);
}
# HTTP authentication
if ($work_list[$bx]->{'http_auth_user'} ne "" && $work_list[$bx]->{'http_auth_pass'} ne "") {
if($config->{'http_check_type'} == 0){
$task_curl_opts .= " --anyauth -u " . safe_param($work_list[$bx]->{'http_auth_user'} . ':' . $work_list[$bx]->{'http_auth_pass'});
}
if ($config->{'http_check_type'} == 1) {
$task_curl_opts .= " --ntlm -u " . safe_param($work_list[$bx]->{'http_auth_user'} . ':' . $work_list[$bx]->{'http_auth_pass'});
}
if ($config->{'http_check_type'} == 2) {
$task_curl_opts .= " --digest -u " . safe_param($work_list[$bx]->{'http_auth_user'} . ':' . $work_list[$bx]->{'http_auth_pass'});
}
if ($config->{'http_check_type'} == 3) {
$task_curl_opts .= " --basic -u " . safe_param($work_list[$bx]->{'http_auth_user'} . ':' . $work_list[$bx]->{'http_auth_pass'});
}
}
# GET
if ($work_list[$bx]->{'type'} eq "GET"){
$task_curl_opts .= " -H 'Accept: text/html'";
if ($cx > 0){
$params = $work_list[$bx]->{'url'} . "?" . $params;
} else {
$params = $work_list[$bx]->{'url'};
}
$resp = curl ($config->{"plugin_exec"}, $timeout, $task_curl_opts, $params, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'}, $config->{"moduleId"}, $config->{"dbh"});
# POST
} elsif ($work_list[$bx]->{'type'} eq "POST") {
$task_curl_opts .= " -d " . safe_param($params);
$task_curl_opts .= " -H 'Content-type: application/x-www-form-urlencoded'";
$resp = curl ($config->{"plugin_exec"}, $timeout, $task_curl_opts, $work_list[$bx]->{'url'}, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'}, $config->{"moduleId"}, $config->{"dbh"});
# HEAD
} else {
$task_curl_opts .= " -I";
if ($cx > 0){
$params = $work_list[$bx]->{'url'} . "?" . uri_escape($params);
} else {
$params = $work_list[$bx]->{'url'};
}
$resp = curl ($config->{"plugin_exec"}, $timeout, $task_curl_opts, $params, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'}, $config->{"moduleId"}, $config->{"dbh"});
}
# Get string ?
if (defined($work_list[$bx]->{'get_string'})) {
my $temp = $work_list[$bx]->{'get_string'};
if ($resp =~ m/($temp)/) {
$task_get_string[$thread_id] = $1;
}
}
# Get response ?
if ($work_list[$bx]->{'get_content_advanced'} ne "") {
my $temp = $work_list[$bx]->{'get_content_advanced'};
if ($resp =~ m/$temp/) {
$task_get_content[$thread_id] = $1 if defined ($1);
}
} elsif ($work_list[$bx]->{'get_content'} ne "") {
my $temp = $work_list[$bx]->{'get_content'};
if ($resp =~ m/($temp)/) {
$task_get_content[$thread_id] = $1;
}
} else {
$task_get_content[$thread_id] = $resp;
}
# Resource bashing
#if ((defined($work_list[$bx]->{'get_resources'})) && ($work_list[$bx]->{'get_resources'} == 1)){
# $total_requests = g_get_all_links ($config, $ua, $resp, $total_requests, $work_list[$bx]->{'url'}, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'});
#}
# CHECKSTRING check
$cx = 0;
while (defined($work_list[$bx]->{'checkstring'}[$cx])) {
my $match_string = $work_list[$bx]->{'checkstring'}[$cx];
my $as_string = $resp;
my $guess = Encode::Guess::guess_encoding($as_string);
if (ref $guess) {
$as_string = $guess->decode($as_string);
}
unless (utf8::is_utf8($match_string)) {
utf8::decode($match_string);
}
if ( $as_string =~ m/$match_string/i ){
$total_valid_requests++;
} else {
$total_invalid_request++;
$bx = $config->{"work_items"}; # Abort session remaining request
$check_string=0;
}
$cx++;
}
# CHECKNOTSTRING check
$cx = 0;
while (defined($work_list[$bx]->{'checknotstring'}[$cx])) {
my $match_string = $work_list[$bx]->{'checknotstring'}[$cx];
my $as_string = $resp;
my $guess = Encode::Guess::guess_encoding($as_string);
if (ref $guess) {
$as_string = $guess->decode($as_string);
}
unless (utf8::is_utf8($match_string)) {
utf8::decode($match_string);
}
if ( $as_string !~ m/$match_string/i ){
$total_valid_requests++;
} else {
$total_invalid_request++;
$bx = $config->{"work_items"}; # Abort session remaining request
$check_string=0;
}
$cx++;
}
# End just now by pressing CTRL-C or Kill Signal !
#if ($goliat_abort == 1){
#$ax = $config->{'retries'};
#$bx = $config->{'items'};
#goto END_LOOP;
#}
} #main work_detail loop
$ttime2 = Time::HiRes::gettimeofday();
$ttime_tot = $ttime2 - $ttime1; # Total time for this task
$task_time[$thread_id] = $ttime_tot;
$task_requests [$thread_id] = $total_requests;
if ($ttime_tot > 0 ){
$task_reqsec[$thread_id] = $total_requests / $ttime_tot;
} else {
$task_reqsec[$thread_id] = $total_requests;
}
$task_fails[$thread_id] = $total_invalid_request;
if ($check_string == 0){
$task_session_fails[$thread_id]++
}
$task_sessions [$thread_id]++;
if ($task_sessions [$thread_id] > 0 ){
$task_ssec[$thread_id] = $ttime_tot / $task_sessions [$thread_id];
} else {
$task_ssec[$thread_id] = $task_sessions[$thread_id];
}
sleep $config->{'ses_delay'};
}
END_LOOP:
if ( -f $cookie_file){
unlink ($cookie_file);
}
$task_end[$thread_id] = 1;
}
# Call CURL and return its output.
sub curl {
my ($exec, $timeout, $curl_opts, $url, $headers, $debug, $moduleId, $dbh) = @_;
while (my ($header, $value) = each %{$headers}) {
$curl_opts .= " -H " . safe_param($header . ':' . $value);
}
my $cmd = "curl $curl_opts " . safe_param($url);
my $response = `"$exec" $timeout $cmd 2>/dev/null`;
if ($? == -1) {
die("Error calling curl. Not enough memory?\n");
}
# Curl command stored for live debugging feature.
set_update_agentmodule ($dbh, $moduleId, { 'debug_content' => $cmd }) if defined($dbh);
return $response if ($debug eq '');
# Debug
if (open (DEBUG, '>>', $debug . '.req')) {
print DEBUG "[Goliat debug " . time () . "]\n";
print DEBUG $cmd;
print "\n";
close (DEBUG);
}
if (open (DEBUG, '>>', $debug . '.res')) {
print DEBUG "[Goliat debug " . time () . "]\n";
print DEBUG $response;
print "\n";
close (DEBUG);
}
return $response;
}
# End of function declaration
# End of defined Code
1;
__END__