#!/usr/bin/perl -w # # WardenClientReceive.pm # # Copyright (C) 2011-2012 Cesnet z.s.p.o # # Use of this source is governed by a BSD-style license, see LICENSE file. package WardenClientReceive; use strict; use SOAP::Lite; use IO::Socket::SSL qw(debug1); use SOAP::Transport::HTTP; use FindBin; use Carp; use Sys::Syslog; our $VERSION = "2.0"; #----- global configuration variables ----------------------------------------- our $LOG_STDERR = 1; our $LOG_SYSLOG = 0; our $LOG_SYSLOG_FACILITY; our $LOG_VERBOSE = 0; #----- end of configuration variables ------------------------------------------ #------------------------------------------------------------------------------- # errMsg - print error message and die #------------------------------------------------------------------------------- sub errMsg { my $msg = "Error message: " . shift; if ($LOG_VERBOSE) { # user wants to log debug information $msg .= "\nStack info: " . Carp::longmess(); } die($msg . "\n"); } # End of errMsg #------------------------------------------------------------------------------- # c2s - connect to server, send request and receive response #------------------------------------------------------------------------------- sub c2s { my $uri = shift; my $ssl_key_file = shift; my $ssl_cert_file = shift; my $ssl_ca_file = shift; my $method = shift; my $data = shift; my $client; my ($server, $port, $service) = $uri =~ /https:\/\/(.+)\:(\d+)\/(.+)/; if (!($client = SOAP::Transport::HTTP::Client->new())) { errMsg("Sorry, unable to create socket: " . &SOAP::Transport::HTTP::Client::errstr) } $client->timeout(10); $client->ssl_opts(verify_hostname => 1, SSL_use_cert => 1, SSL_verify_mode => 0x02, SSL_key_file => $ssl_key_file, SSL_cert_file => $ssl_cert_file, SSL_ca_file => $ssl_ca_file); # setting of URI and serialize SOAP envelope and data object my $soap = SOAP::Lite->uri($service)->proxy($uri); my $envelope; if (!defined $data) { $envelope = $soap->serializer->envelope(method => $method); } else { $envelope = $soap->serializer->envelope(method => $method, $data); } # setting of TCP URI and send serialized SOAP envelope and data my $server_uri = "https://$server:$port/$service"; my $result = $client->send_receive(envelope => $envelope, endpoint => $server_uri); # check server response if (!defined $result) { errMsg("Error: server returned empty response." . "\n" . "Problem with used SSL ceritificates or Warden server at $server:$port is down."); } else { # deserialized response from server -> create SOAP envelope and data object my $response; # test errMsg("test error in c2s()"); eval { $response = $soap->deserializer->deserialize($result); } or errMsg($@ . "Received data: " . $result); # check SOAP fault status $response->fault ? errMsg("Server sent error message:: " . $response->faultstring) : return $response; } } #------------------------------------------------------------------------------- # getNewEvents - get new events from warden server greater than last received ID #------------------------------------------------------------------------------- sub getNewEvents { my @events; eval { my $warden_path = shift; my $requested_type = shift; my $vardir = $warden_path . "/var/"; my $etcdir = $warden_path . "/etc/"; my $libdir = $warden_path . "/lib/"; # read the config file require $libdir . "WardenClientConf.pm"; my $conf_file = $etcdir . "warden-client.conf"; my ($uri, $ssl_key_file, $ssl_cert_file, $ssl_ca_file, $max_rcv_events_limit); ($uri, $ssl_key_file, $ssl_cert_file, $ssl_ca_file, $max_rcv_events_limit, $LOG_STDERR, $LOG_SYSLOG, $LOG_SYSLOG_FACILITY, $LOG_VERBOSE) = WardenClientConf::loadConf($conf_file); # test # errMsg("testovaci error\n"); # set name of ID file for each client aplication my $caller_name = $FindBin::Script; my $id_file = $vardir . $caller_name . ".id"; #----------------------------------------------------------------------------- # get last ID from ID file (if exist) or # get last ID from warden server DB and save it into ID file my $last_id; if (-e $id_file) { open(ID, "< $id_file") || errMsg("Cannot open ID file $id_file: $!"); foreach(<ID>) { $last_id = $_; } close ID; } else { my $response = c2s($uri, $ssl_key_file, $ssl_cert_file, $ssl_ca_file, "getLastId"); $last_id = $response->result; open(ID, "> $id_file") || die ("Cannot open ID file $id_file: $!"); print ID $last_id; close ID; } #----------------------------------------------------------------------------- # get new events from warden server DB based on gathered last ID # create SOAP data obejct my $request_data = SOAP::Data->name( request => \SOAP::Data->value( SOAP::Data->name(REQUESTED_TYPE => $requested_type), SOAP::Data->name(LAST_ID => $last_id), SOAP::Data->name(MAX_RCV_EVENTS_LIMIT => $max_rcv_events_limit) ) ); # call server method getNewEvents my $response = c2s($uri, $ssl_key_file, $ssl_cert_file, $ssl_ca_file, "getNewEvents", $request_data); # parse returned SOAP data object my ($id, $hostname, $service, $detected, $type, $source_type, $source, $target_proto, $target_port, $attack_scale, $note, $priority, $timeout); # my @events; my @response_list = $response->valueof('/Envelope/Body/getNewEventsResponse/event/'); while (scalar @response_list) { my $response_data = shift(@response_list); my @event; # parse items of one event $id = $response_data->{'ID'}; $hostname = $response_data->{'HOSTNAME'}; $service = $response_data->{'SERVICE'}; $detected = $response_data->{'DETECTED'}; $type = $response_data->{'TYPE'}; $source_type = $response_data->{'SOURCE_TYPE'}; $source = $response_data->{'SOURCE'}; $target_proto = $response_data->{'TARGET_PROTO'}; $target_port = $response_data->{'TARGET_PORT'}; $attack_scale = $response_data->{'ATTACK_SCALE'}; $note = $response_data->{'NOTE'}; $priority = $response_data->{'PRIORITY'}; $timeout = $response_data->{'TIMEOUT'}; # push new event from warden server into @events which is returned @event = ($id, $hostname, $service, $detected, $type, $source_type, $source, $target_proto, $target_port, $attack_scale, $note, $priority, $timeout); push (@events, \@event); # set maximum received ID from current batch if ($id > $last_id) { $last_id = $id; } } #end of while loop # write last return ID if (defined $last_id) { # must be defined for first check ID open(ID, "> $id_file") || die ("Cannot open ID file $id_file: $!"); print ID $last_id; close ID; } } # End of eval block or do { if ($LOG_STDERR) { print STDERR "(STDERR)Warden-client unexpected end in eval block.\n" . $@ . "\n"; } if ($LOG_SYSLOG) { #TODO: zapis do syslogu, ne STDERR print STDERR "(SYSLOG)Warden-client unexpected end in eval block.\n" . $@ . "\n"; # openlog("Warden:", "pid", "$LOG_SYSLOG_FACILITY"); # syslog("err|$LOG_SYSLOG_FACILITY", "Warden-client unexpected end in eval block.\n" . $@ . "\n"); # closelog(); } return; }; return @events; } # End of getNewEvents 1;