diff --git a/pandora_agents/unix/tentacle_server b/pandora_agents/unix/tentacle_server index 0d10a5baa8..1e7d21a9d7 100755 --- a/pandora_agents/unix/tentacle_server +++ b/pandora_agents/unix/tentacle_server @@ -30,7 +30,7 @@ tentacle_server - Tentacle Server =head1 VERSION -Version 0.4.0 +Version 0.5.0 =head1 USAGE @@ -86,8 +86,11 @@ my $SOCKET_MODULE = # Service name for Win32. my $SERVICE_NAME="Tentacle Server"; +# Service parameters. +my $SERVICE_PARAMS=join(' ', @ARGV); + # Program version -our $VERSION = '0.4.0'; +our $VERSION = '0.5.0'; # IPv4 address to listen on my @t_addresses = ('0', '0.0.0.0'); @@ -139,7 +142,9 @@ my $t_sem :shared; # Server socket my @t_server_sockets; -my $select; + +# Server select handler +my $t_server_select; # Use SSL, 1 true, 0 false my $t_ssl = 0; @@ -159,10 +164,10 @@ my $t_ssl_pwd = ''; # Timeout for socket read/write operations in seconds my $t_timeout = 1; -#Bridge IP to actuate as a proxy +# Address to proxy client requests to my $t_proxy_ip = undef; -# Proxy port by default 41121 +# Port to proxy client requests to my $t_proxy_port = 41121; # Proxy socket @@ -189,7 +194,7 @@ sub print_help { print ("Tentacle server v$VERSION. See http://www.openideas.info/wiki for protocol description.\n\n"); print ("Options:\n"); print ("\t-a ip_addresses\tIP addresses to listen on (default @t_addresses).\n"); - print ("\t\t(Multiple addresses separated by comma can be defined.)\n"); + print ("\t \t(Multiple addresses separated by comma can be defined.)\n"); print ("\t-c number\tMaximum number of simultaneous connections (default $t_max_conn).\n"); print ("\t-d\t\tRun as daemon.\n"); print ("\t-e cert\t\tOpenSSL certificate file. Enables SSL.\n"); @@ -206,11 +211,11 @@ sub print_help { print ("\t-t time\t\tTime-out for network operations in seconds (default ${t_timeout}s).\n"); print ("\t-v\t\tBe verbose.\n"); print ("\t-w\t\tPrompt for OpenSSL private key password.\n"); - print ("\t-x pwd\t\tServer password.\n\n"); - print ("\t-b proxy_ip_address\t\tProxied server address.\n\n"); - print ("\t-g proxy_port\t\tPort of proxied server.\n\n"); + print ("\t-x pwd\t\tServer password.\n"); + print ("\t-b ip_address\tProxy requests to the given address.\n"); + print ("\t-g port\t\tProxy requests to the given port.\n"); print ("\t-T\t\tEnable tcpwrappers support.\n"); - print ("\t\t(To use this option, 'Authen::Libwrap' should be installed.)\n\n"); + print ("\t \t\t(To use this option, 'Authen::Libwrap' should be installed.)\n\n"); } ################################################################################ @@ -261,6 +266,23 @@ sub parse_options { exit 1; } + # The Win32 service must be installed/uninstalled without checking other parameters. + if (defined ($opts{'S'})) { + my $service_action = $opts{'S'}; + if ($^O ne 'MSWin32') { + error ("Windows services are only available on Win32."); + } else { + eval "use Win32::Daemon"; + die($@) if ($@); + + if ($service_action eq 'install') { + install_service(); + } elsif ($service_action eq 'uninstall') { + uninstall_service(); + } + } + } + # Address if (defined ($opts{'a'})) { @t_addresses = (); @@ -462,11 +484,7 @@ sub parse_options { eval "use Win32::Daemon"; die($@) if ($@); - if ($service_action eq 'install') { - install_service(); - } elsif ($service_action eq 'uninstall') { - uninstall_service(); - } elsif ($service_action eq 'run') { + if ($service_action eq 'run') { Win32::Daemon::RegisterCallbacks({ start => \&callback_start, running => \&callback_running, @@ -483,9 +501,9 @@ sub parse_options { ################################################################################ ## SUB start_proxy -## Open the server socket. +## Open the proxy server socket. ################################################################################ -sub open_proxy { +sub start_proxy { # Connect to server $t_proxy_socket = $SOCKET_MODULE->new ( @@ -498,8 +516,8 @@ sub open_proxy { } # Create proxy selector - $t_proxy_select = IO::Select->new (); - $t_proxy_select->add ($t_proxy_socket); + $t_proxy_select = IO::Select->new (); + $t_proxy_select->add ($t_proxy_socket); } @@ -538,11 +556,11 @@ sub start_server { if (!@t_server_sockets) { error ("Cannot open socket for all addresses on port $t_port: $!."); - } + } - $select = IO::Select->new(); + $t_server_select = IO::Select->new(); foreach my $t_server_socket (@t_server_sockets){ - $select->add($t_server_socket); + $t_server_select->add($t_server_socket); } } @@ -601,8 +619,6 @@ sub send_data_proxy { ################################################################################ sub close_proxy { $t_proxy_socket->close (); - print_log ("Proxy socket closed"); - } ################################################################################ @@ -666,6 +682,9 @@ sub accept_connections { my $pid; my $t_server_socket; + # Ignore SIGPIPE errors (happens on FreeBSD when SSL is enabled ¿?) + $SIG{PIPE} = 'IGNORE'; + # Start server start_server (); @@ -673,7 +692,7 @@ sub accept_connections { $t_sem = Thread::Semaphore->new ($t_max_conn); while (1) { - my @ready = $select->can_read; + my @ready = $t_server_select->can_read; foreach $t_server_socket (@ready) { # Accept connection @@ -744,40 +763,25 @@ sub serve_client() { ## Actuate as a proxy between its client and other tentacle server. ################################################################################ sub serve_proxy_connection { - my $read; - my $data=1; - # Start a connection with the other Tentacle Server - open_proxy(); - - my $command; + # We are a proxy! Start a connection to the Tentacle Server. + start_proxy(); - # Read commands - while ($command = recv_command ($t_block_size)) { - # Client wants to send a file - if ($command =~ /^SEND <(.*)> SIZE (\d+)$/) { - recv_file_proxy($command, $2); + # Forward data between the client and the server. + eval { + while (1) { + if ($t_select->can_read(0)) { + my ($read, $data) = recv_data($t_block_size); + send_data_proxy($data); + } + if ($t_proxy_select->can_read(0)) { + my ($read, $data) = recv_data_proxy($t_block_size); + send_data($data); + } } - # Client wants to receive a file - elsif ($command =~ /^RECV <(.*)>$/) { - send_file_proxy ($command); - } - # Quit - elsif ($command =~ /^QUIT$/) { - print_log ("Connection closed from " . $t_client_socket->sockhost ()); - - # End proxy connection - send_data_proxy("QUIT\n"); - last; - } - # Unknown command - else { - print_log ("Unknown command '$command' from " . $t_client_socket->sockhost ()); - last; - } - } + }; - # End a connection with the other Tentacle Server + # Close the connection to the Tentacle Server. close_proxy(); } @@ -843,43 +847,6 @@ sub auth_pwd { send_data ("PASS OK\n"); } -################################################################################ -## SUB recv_file_proxy -## Redirect file from agent to proxy -################################################################################ -sub recv_file_proxy ($$) { - my ($command, $size) = @_; - - # Send command to proxy - print_log ("[PROXY] Host: ".$t_client_socket->sockhost()." send ".$command." to ".$t_proxy_socket->sockhost ()); - send_data_proxy($command."\n"); - - # Proxied server response - my $rc = dump_data($t_proxy_socket, $t_client_socket); - - # Check if there was an error - if ($rc == -1) { - return; - } - - # Client send data to server - $rc = dump_data($t_client_socket, $t_proxy_socket, $size); - - # Check if there was an error - if ($rc == -1) { - return; - } - - # Server says if data was recieved or not - $rc = dump_data($t_proxy_socket, $t_client_socket); - - # Check if there was an error - if ($rc == -1) { - return; - } - -} - ################################################################################ ## SUB recv_file ## Receive a file of size $_[1] and save it in $t_directory as $_[0]. @@ -929,45 +896,6 @@ sub recv_file { print_log ("Received file '$base_name' size ${size}b from " . $t_client_socket->sockhost ()); } -################################################################################ -## SUB send_file_proxy -## Redirect file from agent to proxy -################################################################################ -sub send_file_proxy ($) { - my ($command) = @_; - my $size; - # Send command to proxy - print_log ("[PROXY] ".$t_client_socket->sockhost()." send ".$command." to ".$t_proxy_socket->sockhost ()); - send_data_proxy($command."\n"); - - $command = recv_command_proxy($t_block_size); - - if ($command =~ /^RECV SIZE (\d+)$/) { - $size = $1; - } - - print_log ("[PROXY] ".$t_proxy_socket->sockhost()." send ".$command." to ".$t_client_socket->sockhost ()); - - send_data($command."\n"); - - # Client send OK to server - my $rc = dump_data($t_client_socket, $t_proxy_socket); - - # Check if there was an error - if ($rc == -1) { - return; - } - - # Proxied server send the file to client - $rc = dump_data($t_proxy_socket, $t_client_socket, $size); - - # Check if there was an error - if ($rc == -1) { - return; - } - -} - ################################################################################ ## SUB send_file ## Send a file to the client @@ -1176,127 +1104,6 @@ sub send_data { } } -################################################################################ -## SUB dump_data -## Dump data from a socket to another one. Following Tentacle Protocol. -################################################################################ -sub dump_data($$;$) { - my ($from, $to, $size) = @_; - my $read; - my $data; - my $buffer = ""; - my $written; - my $total = $size; - my $t_select_read = undef; - my $t_select_write = undef; - - # Assign the correct selector for each socket - if ($from == $t_proxy_socket) { - # We must read from t_proxy_socket - $t_select_read = $t_proxy_select; - $t_select_write = $t_select; - } else { - # We must read from t_client_socket - $t_select_read = $t_select; - $t_select_write = $t_proxy_select; - } - - while (1) { - - # Ensure we can read from socket - if ($t_select_read->can_read()) { - # Ensure we can write from socket - if ($t_select_write->can_write()) { - - $read = ""; - $read = sysread ($from, $data, $t_block_size); - - # Read error - if (! defined ($read)) { - error ("Read error from " . $from->sockhost () . ": $!."); - return -1; - } - - # EOF - if ($read == 0) { - error ("Connection from " . $from->sockhost () . " unexpectedly closed."); - return -1; - } - - $written = syswrite ($to, $data, $read); - - if ($written != $read) { - error ("Connection from " . $to->sockhost () . " unexpectedly closed."); - return -1; - } - - $buffer .= $data; - - if (! defined ($size)) { - # If no size defined check for \n - # because a command was sent. - - if ($buffer =~ /\n$/) { - - # Delete CHAR \n - chop($buffer); - - print_log ("[PROXY] ".$from->sockhost()." send ".$buffer." to ".$to->sockhost ()); - - # Returns error if proxy returns error to end connection - if ($buffer =~ /SEND ERR/) { - return -1; - } else { - return 0; - } - } - } else { - # If size is defined check if all bytes were sent - $size = $size - $read; - - if ($size == 0) { - print_log ("[PROXY] ".$from->sockhost()." send ".$total."b to ".$to->sockhost()); - - return 0; - } - } - } - } - } -} - -################################################################################ -## SUB recv_command_proxy -## Read a command from the proxied server, ended by a new line character. -################################################################################ -sub recv_command_proxy { - my $buffer; - my $char; - my $command = ''; - my $read; - my $total = 0; - - while (1) { - - ($read, $buffer) = recv_data_proxy ($t_block_size); - $command .= $buffer; - $total += $read; - - # Check if the command is complete - $char = chop ($command); - if ($char eq "\n") { - return $command; - } - - $command .= $char; - - # Avoid overflow - if ($total > $t_block_size) { - error ("Received too much data from " . $t_proxy_socket->sockhost () . "."); - } - } -} - ################################################################################ ## SUB recv_command ## Read a command from the client, ended by a new line character. @@ -1414,7 +1221,10 @@ sub apply_filters ($) { sub install_service() { my $service_path = $0; - my $service_params = "-s \"$t_directory\" -S run"; + my $service_params = $SERVICE_PARAMS; + + # Change the service parameter from 'install' to 'run'. + $service_params =~ s/\-S\s+\S+/\-S run/; my %service_hash = ( machine => '',