369 lines
10 KiB
Perl
Executable File
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__
|