Update Tentacle to the latest version.
Ref pandora_enterprise#2360.
This commit is contained in:
parent
0a61a5f5d3
commit
0f4ea33667
|
@ -58,6 +58,8 @@ use strict;
|
||||||
use File::Basename;
|
use File::Basename;
|
||||||
use Getopt::Std;
|
use Getopt::Std;
|
||||||
use IO::Select;
|
use IO::Select;
|
||||||
|
use IO::Compress::Zip qw(zip $ZipError);
|
||||||
|
use IO::Uncompress::Unzip qw(unzip $UnzipError);
|
||||||
use Socket (qw(SOCK_STREAM AF_INET AF_INET6));
|
use Socket (qw(SOCK_STREAM AF_INET AF_INET6));
|
||||||
my $SOCKET_MODULE =
|
my $SOCKET_MODULE =
|
||||||
eval { require IO::Socket::INET6 } ? 'IO::Socket::INET6'
|
eval { require IO::Socket::INET6 } ? 'IO::Socket::INET6'
|
||||||
|
@ -131,6 +133,12 @@ my $t_ssl_pwd = '';
|
||||||
# Timeout for socket read/write operations in seconds
|
# Timeout for socket read/write operations in seconds
|
||||||
my $t_timeout = 1;
|
my $t_timeout = 1;
|
||||||
|
|
||||||
|
# bind ipaddr
|
||||||
|
my $t_bind_address = undef;
|
||||||
|
|
||||||
|
# Compress data before sending it through the socket.
|
||||||
|
my $t_zip = 0;
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
## SUB print_help
|
## SUB print_help
|
||||||
## Print help screen.
|
## Print help screen.
|
||||||
|
@ -141,6 +149,7 @@ sub print_help {
|
||||||
print ("Tentacle client v$VERSION. See http://www.openideas.info/wiki for protocol description.\n\n");
|
print ("Tentacle client v$VERSION. See http://www.openideas.info/wiki for protocol description.\n\n");
|
||||||
print ("Options:\n");
|
print ("Options:\n");
|
||||||
print ("\t-a address\tServer address (default $t_address).\n");
|
print ("\t-a address\tServer address (default $t_address).\n");
|
||||||
|
print ("\t-b localaddress\tLocal address to bind.\n");
|
||||||
print ("\t-c\t\tEnable SSL without a client certificate.\n");
|
print ("\t-c\t\tEnable SSL without a client certificate.\n");
|
||||||
print ("\t-e cert\t\tOpenSSL certificate file. Enables SSL.\n");
|
print ("\t-e cert\t\tOpenSSL certificate file. Enables SSL.\n");
|
||||||
print ("\t-f ca\t\tVerify that the peer certificate is signed by a ca.\n");
|
print ("\t-f ca\t\tVerify that the peer certificate is signed by a ca.\n");
|
||||||
|
@ -154,7 +163,8 @@ sub print_help {
|
||||||
print ("\t-v\t\tBe verbose.\n");
|
print ("\t-v\t\tBe verbose.\n");
|
||||||
print ("\t-w\t\tPrompt for OpenSSL private key password.\n");
|
print ("\t-w\t\tPrompt for OpenSSL private key password.\n");
|
||||||
print ("\t-x pwd\t\tServer password.\n");
|
print ("\t-x pwd\t\tServer password.\n");
|
||||||
print ("\t-y proxy\tProxy server string (user:password\@address:port).\n\n");
|
print ("\t-y proxy\tProxy server string (user:password\@address:port).\n");
|
||||||
|
print ("\t-z Compress data.\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -166,7 +176,7 @@ sub parse_options {
|
||||||
my $tmp;
|
my $tmp;
|
||||||
|
|
||||||
# Get options
|
# Get options
|
||||||
if (getopts ('a:ce:f:ghk:p:qr:t:vwx:y:', \%opts) == 0 || defined ($opts{'h'})) {
|
if (getopts ('a:b:ce:f:ghk:p:qr:t:vwx:y:z', \%opts) == 0 || defined ($opts{'h'})) {
|
||||||
print_help ();
|
print_help ();
|
||||||
exit 1;
|
exit 1;
|
||||||
}
|
}
|
||||||
|
@ -183,6 +193,18 @@ sub parse_options {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Bind local address
|
||||||
|
if (defined ($opts{'b'})) {
|
||||||
|
$t_bind_address = $opts{'b'};
|
||||||
|
if (($t_bind_address !~ /^[a-zA-Z\.][a-zA-Z0-9\.\-]+$/ && ($t_bind_address !~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
|
||||||
|
|| $1 < 0 || $1 > 255 || $2 < 0 || $2 > 255
|
||||||
|
|| $3 < 0 || $3 > 255 || $4 < 0 || $4 > 255)) &&
|
||||||
|
($t_address !~ /^[0-9a-f:]+$/o)) {
|
||||||
|
error ("Local address $t_bind_address is not valid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
# Enable SSL without a client certificate
|
# Enable SSL without a client certificate
|
||||||
if (defined ($opts{'c'})) {
|
if (defined ($opts{'c'})) {
|
||||||
require IO::Socket::SSL;
|
require IO::Socket::SSL;
|
||||||
|
@ -299,6 +321,11 @@ sub parse_options {
|
||||||
error ("Proxy port $t_proxy_port is not valid.");
|
error ("Proxy port $t_proxy_port is not valid.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Compress data
|
||||||
|
if (defined ($opts{'z'})) {
|
||||||
|
$t_zip = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -309,6 +336,16 @@ sub start_client {
|
||||||
|
|
||||||
# Connect to server
|
# Connect to server
|
||||||
if ($SOCKET_MODULE ne 'IO::Socket::INET') {
|
if ($SOCKET_MODULE ne 'IO::Socket::INET') {
|
||||||
|
if (defined ($t_bind_address)) {
|
||||||
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
|
Domain => AF_INET6,
|
||||||
|
PeerAddr => $t_address,
|
||||||
|
PeerPort => $t_port,
|
||||||
|
LocalAddr => $t_bind_address,
|
||||||
|
Type => SOCK_STREAM
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
$t_socket = $SOCKET_MODULE->new (
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
Domain => AF_INET6,
|
Domain => AF_INET6,
|
||||||
PeerAddr => $t_address,
|
PeerAddr => $t_address,
|
||||||
|
@ -316,7 +353,18 @@ sub start_client {
|
||||||
Type => SOCK_STREAM
|
Type => SOCK_STREAM
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (! defined ($t_socket)) {
|
if (! defined ($t_socket)) {
|
||||||
|
if (defined ($t_bind_address)) {
|
||||||
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
|
Domain => AF_INET,
|
||||||
|
PeerAddr => $t_address,
|
||||||
|
PeerPort => $t_port,
|
||||||
|
LocalAddr => $t_bind_address,
|
||||||
|
Type => SOCK_STREAM
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
$t_socket = $SOCKET_MODULE->new (
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
Domain => AF_INET,
|
Domain => AF_INET,
|
||||||
PeerAddr => $t_address,
|
PeerAddr => $t_address,
|
||||||
|
@ -324,6 +372,7 @@ sub start_client {
|
||||||
Type => SOCK_STREAM
|
Type => SOCK_STREAM
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (! defined ($t_socket)) {
|
if (! defined ($t_socket)) {
|
||||||
error ("Cannot connect to $t_address on port $t_port: $!.");
|
error ("Cannot connect to $t_address on port $t_port: $!.");
|
||||||
|
@ -344,19 +393,39 @@ sub start_client_proxy {
|
||||||
|
|
||||||
# Connect to proxy
|
# Connect to proxy
|
||||||
if ($SOCKET_MODULE ne 'IO::Socket::INET') {
|
if ($SOCKET_MODULE ne 'IO::Socket::INET') {
|
||||||
|
if (defined ($t_bind_address)) {
|
||||||
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
|
Domain => AF_INET6,
|
||||||
|
PeerAddr => $t_proxy_address,
|
||||||
|
PeerPort => $t_proxy_port,
|
||||||
|
LocalAddr => $t_bind_address,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
$t_socket = $SOCKET_MODULE->new (
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
Domain => AF_INET6,
|
Domain => AF_INET6,
|
||||||
PeerAddr => $t_proxy_address,
|
PeerAddr => $t_proxy_address,
|
||||||
PeerPort => $t_proxy_port,
|
PeerPort => $t_proxy_port,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (! defined ($t_socket)) {
|
if (! defined ($t_socket)) {
|
||||||
|
if (defined ($t_bind_address)) {
|
||||||
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
|
Domain => AF_INET,
|
||||||
|
PeerAddr => $t_proxy_address,
|
||||||
|
PeerPort => $t_proxy_port,
|
||||||
|
LocalAddr => $t_bind_address,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
$t_socket = $SOCKET_MODULE->new (
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
Domain => AF_INET,
|
Domain => AF_INET,
|
||||||
PeerAddr => $t_proxy_address,
|
PeerAddr => $t_proxy_address,
|
||||||
PeerPort => $t_proxy_port,
|
PeerPort => $t_proxy_port,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (! defined ($t_socket)) {
|
if (! defined ($t_socket)) {
|
||||||
error ("Cannot connect to proxy server $t_proxy_address on port $t_proxy_port: $!.");
|
error ("Cannot connect to proxy server $t_proxy_address on port $t_proxy_port: $!.");
|
||||||
|
@ -408,6 +477,8 @@ sub start_ssl {
|
||||||
if ($t_ssl_cert eq ''){
|
if ($t_ssl_cert eq ''){
|
||||||
IO::Socket::SSL->start_SSL (
|
IO::Socket::SSL->start_SSL (
|
||||||
$t_socket,
|
$t_socket,
|
||||||
|
# No authentication
|
||||||
|
SSL_verify_mode => 0x00,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
elsif ($t_ssl_ca eq '') {
|
elsif ($t_ssl_ca eq '') {
|
||||||
|
@ -525,6 +596,46 @@ sub recv_file {
|
||||||
print_log ("Received file '$file'");
|
print_log ("Received file '$file'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## SUB zrecv_file
|
||||||
|
## Receive a compressed file from the server
|
||||||
|
################################################################################
|
||||||
|
sub zrecv_file {
|
||||||
|
my $data = '';
|
||||||
|
my $file = $_[0];
|
||||||
|
my $response;
|
||||||
|
my $size;
|
||||||
|
my $zdata = '';
|
||||||
|
|
||||||
|
# Request file
|
||||||
|
send_data ("ZRECV <$file>\n");
|
||||||
|
|
||||||
|
# Wait for server response
|
||||||
|
$response = recv_command ();
|
||||||
|
if ($response !~ /^ZRECV SIZE (\d+)$/) {
|
||||||
|
error ("Server responded $response.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$size = $1;
|
||||||
|
send_data ("ZRECV OK\n");
|
||||||
|
|
||||||
|
# Receive file
|
||||||
|
$zdata = recv_data_block ($size);
|
||||||
|
if (!unzip(\$zdata => \$data)) {
|
||||||
|
print_log ("Uncompress error: $UnzipError");
|
||||||
|
send_data ("ZRECV ERR\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Write it to disk
|
||||||
|
open (FILE, "> $file") || error ("Cannot open file '$file' for writing.");
|
||||||
|
binmode (FILE);
|
||||||
|
print (FILE $data);
|
||||||
|
close (FILE);
|
||||||
|
|
||||||
|
print_log ("Received compressed file '$file'");
|
||||||
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
## SUB send_file
|
## SUB send_file
|
||||||
## Send a file to the server
|
## Send a file to the server
|
||||||
|
@ -578,6 +689,55 @@ sub send_file {
|
||||||
print_log ("File sent");
|
print_log ("File sent");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## SUB zsend_file
|
||||||
|
## Send a file to the server (compressed)
|
||||||
|
################################################################################
|
||||||
|
sub zsend_file {
|
||||||
|
my $base_name;
|
||||||
|
my $data = '';
|
||||||
|
my $response = '';
|
||||||
|
my $retries;
|
||||||
|
my $file = $_[0];
|
||||||
|
my $size;
|
||||||
|
my $written;
|
||||||
|
|
||||||
|
# Read the file and compress its contents
|
||||||
|
if (! zip($file => \$data)) {
|
||||||
|
send_data ("QUIT\n");
|
||||||
|
error ("Compression error: $ZipError");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$size = length($data);
|
||||||
|
$base_name = basename ($file);
|
||||||
|
|
||||||
|
# Request to send file
|
||||||
|
send_data ("ZSEND <$base_name> SIZE $size\n");
|
||||||
|
print_log ("Request to send file '$base_name' size ${size}b (compressed)");
|
||||||
|
|
||||||
|
# Wait for server response
|
||||||
|
$response = recv_command ();
|
||||||
|
|
||||||
|
# Server rejected the file
|
||||||
|
if ($response ne "ZSEND OK") {
|
||||||
|
send_data ("QUIT\n");
|
||||||
|
error ("Server responded $response.");
|
||||||
|
}
|
||||||
|
|
||||||
|
print_log ("Server responded SEND OK");
|
||||||
|
send_data ($data);
|
||||||
|
|
||||||
|
# Wait for server response
|
||||||
|
$response = recv_command ();
|
||||||
|
if ($response ne "ZSEND OK") {
|
||||||
|
send_data ("QUIT\n");
|
||||||
|
error ("Server responded $response.");
|
||||||
|
}
|
||||||
|
|
||||||
|
print_log ("File sent");
|
||||||
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Common functions
|
# Common functions
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -830,15 +990,23 @@ if ($t_recv == 0) {
|
||||||
|
|
||||||
# Send the files
|
# Send the files
|
||||||
foreach $file (@ARGV) {
|
foreach $file (@ARGV) {
|
||||||
|
if ($t_zip == 1) {
|
||||||
|
zsend_file($file);
|
||||||
|
} else {
|
||||||
send_file ($file);
|
send_file ($file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
# Send the files
|
# Receive the files
|
||||||
foreach $file (@ARGV) {
|
foreach $file (@ARGV) {
|
||||||
|
if ($t_zip == 1) {
|
||||||
|
zrecv_file ($file);
|
||||||
|
} else {
|
||||||
recv_file ($file);
|
recv_file ($file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Tell the server that we are finished
|
# Tell the server that we are finished
|
||||||
send_data ("QUIT\n");
|
send_data ("QUIT\n");
|
||||||
|
@ -882,6 +1050,8 @@ __END__
|
||||||
|
|
||||||
=item I<-x pwd> B<Server password>.
|
=item I<-x pwd> B<Server password>.
|
||||||
|
|
||||||
|
=item I<-z> Compress data.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 EXIT STATUS
|
=head1 EXIT STATUS
|
||||||
|
|
|
@ -60,6 +60,8 @@ use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Getopt::Std;
|
use Getopt::Std;
|
||||||
use IO::Select;
|
use IO::Select;
|
||||||
|
use IO::Compress::Zip qw(zip $ZipError);
|
||||||
|
use IO::Uncompress::Unzip qw(unzip $UnzipError);
|
||||||
use threads;
|
use threads;
|
||||||
use Thread::Semaphore;
|
use Thread::Semaphore;
|
||||||
use POSIX ":sys_wait_h";
|
use POSIX ":sys_wait_h";
|
||||||
|
@ -959,6 +961,15 @@ sub serve_connection {
|
||||||
print_info ("Request to receive file '$1' from " . $t_client_socket->sockhost ());
|
print_info ("Request to receive file '$1' from " . $t_client_socket->sockhost ());
|
||||||
send_file ($1);
|
send_file ($1);
|
||||||
}
|
}
|
||||||
|
elsif ($command =~ /^ZSEND <(.*)> SIZE (\d+)$/) {
|
||||||
|
print_info ("Request to send compressed file '$1' size ${2}b from " . $t_client_socket->sockhost ());
|
||||||
|
zrecv_file ($1, $2);
|
||||||
|
}
|
||||||
|
# Client wants to receive a file
|
||||||
|
elsif ($command =~ /^ZRECV <(.*)>$/) {
|
||||||
|
print_info ("Request to receive compressed file '$1' from " . $t_client_socket->sockhost ());
|
||||||
|
zsend_file ($1);
|
||||||
|
}
|
||||||
# Quit
|
# Quit
|
||||||
elsif ($command =~ /^QUIT$/) {
|
elsif ($command =~ /^QUIT$/) {
|
||||||
print_info ("Connection closed from " . $t_client_socket->sockhost ());
|
print_info ("Connection closed from " . $t_client_socket->sockhost ());
|
||||||
|
@ -1070,6 +1081,61 @@ sub recv_file {
|
||||||
print_info ("Received file '$base_name' size ${size}b from " . $t_client_socket->sockhost ());
|
print_info ("Received file '$base_name' size ${size}b from " . $t_client_socket->sockhost ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## SUB zrecv_file
|
||||||
|
## Receive a compressed file of size $_[1] and save it in $t_directory as $_[0].
|
||||||
|
################################################################################
|
||||||
|
sub zrecv_file {
|
||||||
|
my $base_name = $_[0];
|
||||||
|
my $data = '';
|
||||||
|
my $file;
|
||||||
|
my $size = $_[1];
|
||||||
|
my $zdata = '';
|
||||||
|
|
||||||
|
# Check file name
|
||||||
|
if ($base_name =~ /[$t_invalid_chars]/) {
|
||||||
|
print_log ("File '$base_name' size ${size}b from " . $t_client_socket->sockhost () . " has an invalid file name");
|
||||||
|
send_data ("ZSEND ERR (invalid file name)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check file size, empty files are not allowed
|
||||||
|
if ($size < 1 || $size > $t_max_size) {
|
||||||
|
print_log ("File '$base_name' size ${size}b from " . $t_client_socket->sockhost () . " is too big");
|
||||||
|
send_data ("ZSEND ERR (file is too big)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Apply filters
|
||||||
|
$file = "$t_directory/" . apply_filters ($base_name) . $base_name;
|
||||||
|
|
||||||
|
# Check if file exists
|
||||||
|
if (-f $file && $t_overwrite == 0) {
|
||||||
|
print_log ("File '$base_name' size ${size}b from " . $t_client_socket->sockhost () . " already exists");
|
||||||
|
send_data ("ZSEND ERR (file already exists)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_data ("ZSEND OK\n");
|
||||||
|
|
||||||
|
# Receive file
|
||||||
|
$zdata = recv_data_block ($size);
|
||||||
|
if (!unzip(\$zdata => \$data)) {
|
||||||
|
print_log ("Uncompress error: $UnzipError");
|
||||||
|
send_data ("ZSEND ERR\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Write it to disk
|
||||||
|
open (FILE, "> $file") || error ("Cannot open file '$file' for writing.");
|
||||||
|
binmode (FILE);
|
||||||
|
print (FILE $data);
|
||||||
|
close (FILE);
|
||||||
|
|
||||||
|
send_data ("ZSEND OK\n");
|
||||||
|
print_info ("Received compressed file '$base_name' size ${size}b from " . $t_client_socket->sockhost ());
|
||||||
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
## SUB send_file
|
## SUB send_file
|
||||||
## Send a file to the client
|
## Send a file to the client
|
||||||
|
@ -1122,6 +1188,57 @@ sub send_file {
|
||||||
print_log ("Requested file '$file' from " . $t_client_socket->sockhost () . " sent");
|
print_log ("Requested file '$file' from " . $t_client_socket->sockhost () . " sent");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## SUB zsend_file
|
||||||
|
## Send a file to the client
|
||||||
|
################################################################################
|
||||||
|
sub zsend_file {
|
||||||
|
my $base_name = $_[0];
|
||||||
|
my $data = '';
|
||||||
|
my $file;
|
||||||
|
my $response;
|
||||||
|
my $size;
|
||||||
|
|
||||||
|
# Check file name
|
||||||
|
if ($base_name =~ /[$t_invalid_chars]/) {
|
||||||
|
print_log ("Requested compressed file '$base_name' from " . $t_client_socket->sockhost () . " has an invalid file name");
|
||||||
|
send_data ("ZRECV ERR (file has an invalid file name)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Apply filters
|
||||||
|
$file = "$t_directory/" . apply_filters ($base_name) . $base_name;
|
||||||
|
|
||||||
|
# Check if file exists
|
||||||
|
if (! -f $file) {
|
||||||
|
print_log ("Requested compressed '$file' from " . $t_client_socket->sockhost () . " does not exist");
|
||||||
|
send_data ("ZRECV ERR (file does not exist)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Read the file and compress its contents
|
||||||
|
if (! zip($file => \$data)) {
|
||||||
|
send_data ("QUIT\n");
|
||||||
|
error ("Compression error: $ZipError");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$size = length($data);
|
||||||
|
send_data ("ZRECV SIZE $size\n");
|
||||||
|
|
||||||
|
# Wait for client response
|
||||||
|
$response = recv_command ($t_block_size);
|
||||||
|
if ($response ne "ZRECV OK") {
|
||||||
|
print_log ("Requested compressed '$file' from " . $t_client_socket->sockhost () . " not sent");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Send the file
|
||||||
|
send_data ($data);
|
||||||
|
|
||||||
|
print_log ("Requested compressed '$file' from " . $t_client_socket->sockhost () . " sent");
|
||||||
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Common functions
|
# Common functions
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
|
@ -58,6 +58,8 @@ use strict;
|
||||||
use File::Basename;
|
use File::Basename;
|
||||||
use Getopt::Std;
|
use Getopt::Std;
|
||||||
use IO::Select;
|
use IO::Select;
|
||||||
|
use IO::Compress::Zip qw(zip $ZipError);
|
||||||
|
use IO::Uncompress::Unzip qw(unzip $UnzipError);
|
||||||
use Socket (qw(SOCK_STREAM AF_INET AF_INET6));
|
use Socket (qw(SOCK_STREAM AF_INET AF_INET6));
|
||||||
my $SOCKET_MODULE =
|
my $SOCKET_MODULE =
|
||||||
eval { require IO::Socket::INET6 } ? 'IO::Socket::INET6'
|
eval { require IO::Socket::INET6 } ? 'IO::Socket::INET6'
|
||||||
|
@ -131,6 +133,12 @@ my $t_ssl_pwd = '';
|
||||||
# Timeout for socket read/write operations in seconds
|
# Timeout for socket read/write operations in seconds
|
||||||
my $t_timeout = 1;
|
my $t_timeout = 1;
|
||||||
|
|
||||||
|
# bind ipaddr
|
||||||
|
my $t_bind_address = undef;
|
||||||
|
|
||||||
|
# Compress data before sending it through the socket.
|
||||||
|
my $t_zip = 0;
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
## SUB print_help
|
## SUB print_help
|
||||||
## Print help screen.
|
## Print help screen.
|
||||||
|
@ -141,6 +149,7 @@ sub print_help {
|
||||||
print ("Tentacle client v$VERSION. See http://www.openideas.info/wiki for protocol description.\n\n");
|
print ("Tentacle client v$VERSION. See http://www.openideas.info/wiki for protocol description.\n\n");
|
||||||
print ("Options:\n");
|
print ("Options:\n");
|
||||||
print ("\t-a address\tServer address (default $t_address).\n");
|
print ("\t-a address\tServer address (default $t_address).\n");
|
||||||
|
print ("\t-b localaddress\tLocal address to bind.\n");
|
||||||
print ("\t-c\t\tEnable SSL without a client certificate.\n");
|
print ("\t-c\t\tEnable SSL without a client certificate.\n");
|
||||||
print ("\t-e cert\t\tOpenSSL certificate file. Enables SSL.\n");
|
print ("\t-e cert\t\tOpenSSL certificate file. Enables SSL.\n");
|
||||||
print ("\t-f ca\t\tVerify that the peer certificate is signed by a ca.\n");
|
print ("\t-f ca\t\tVerify that the peer certificate is signed by a ca.\n");
|
||||||
|
@ -154,7 +163,8 @@ sub print_help {
|
||||||
print ("\t-v\t\tBe verbose.\n");
|
print ("\t-v\t\tBe verbose.\n");
|
||||||
print ("\t-w\t\tPrompt for OpenSSL private key password.\n");
|
print ("\t-w\t\tPrompt for OpenSSL private key password.\n");
|
||||||
print ("\t-x pwd\t\tServer password.\n");
|
print ("\t-x pwd\t\tServer password.\n");
|
||||||
print ("\t-y proxy\tProxy server string (user:password\@address:port).\n\n");
|
print ("\t-y proxy\tProxy server string (user:password\@address:port).\n");
|
||||||
|
print ("\t-z Compress data.\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -166,7 +176,7 @@ sub parse_options {
|
||||||
my $tmp;
|
my $tmp;
|
||||||
|
|
||||||
# Get options
|
# Get options
|
||||||
if (getopts ('a:ce:f:ghk:p:qr:t:vwx:y:', \%opts) == 0 || defined ($opts{'h'})) {
|
if (getopts ('a:b:ce:f:ghk:p:qr:t:vwx:y:z', \%opts) == 0 || defined ($opts{'h'})) {
|
||||||
print_help ();
|
print_help ();
|
||||||
exit 1;
|
exit 1;
|
||||||
}
|
}
|
||||||
|
@ -183,6 +193,18 @@ sub parse_options {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Bind local address
|
||||||
|
if (defined ($opts{'b'})) {
|
||||||
|
$t_bind_address = $opts{'b'};
|
||||||
|
if (($t_bind_address !~ /^[a-zA-Z\.][a-zA-Z0-9\.\-]+$/ && ($t_bind_address !~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
|
||||||
|
|| $1 < 0 || $1 > 255 || $2 < 0 || $2 > 255
|
||||||
|
|| $3 < 0 || $3 > 255 || $4 < 0 || $4 > 255)) &&
|
||||||
|
($t_address !~ /^[0-9a-f:]+$/o)) {
|
||||||
|
error ("Local address $t_bind_address is not valid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
# Enable SSL without a client certificate
|
# Enable SSL without a client certificate
|
||||||
if (defined ($opts{'c'})) {
|
if (defined ($opts{'c'})) {
|
||||||
require IO::Socket::SSL;
|
require IO::Socket::SSL;
|
||||||
|
@ -299,6 +321,11 @@ sub parse_options {
|
||||||
error ("Proxy port $t_proxy_port is not valid.");
|
error ("Proxy port $t_proxy_port is not valid.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Compress data
|
||||||
|
if (defined ($opts{'z'})) {
|
||||||
|
$t_zip = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -309,6 +336,16 @@ sub start_client {
|
||||||
|
|
||||||
# Connect to server
|
# Connect to server
|
||||||
if ($SOCKET_MODULE ne 'IO::Socket::INET') {
|
if ($SOCKET_MODULE ne 'IO::Socket::INET') {
|
||||||
|
if (defined ($t_bind_address)) {
|
||||||
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
|
Domain => AF_INET6,
|
||||||
|
PeerAddr => $t_address,
|
||||||
|
PeerPort => $t_port,
|
||||||
|
LocalAddr => $t_bind_address,
|
||||||
|
Type => SOCK_STREAM
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
$t_socket = $SOCKET_MODULE->new (
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
Domain => AF_INET6,
|
Domain => AF_INET6,
|
||||||
PeerAddr => $t_address,
|
PeerAddr => $t_address,
|
||||||
|
@ -316,7 +353,18 @@ sub start_client {
|
||||||
Type => SOCK_STREAM
|
Type => SOCK_STREAM
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (! defined ($t_socket)) {
|
if (! defined ($t_socket)) {
|
||||||
|
if (defined ($t_bind_address)) {
|
||||||
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
|
Domain => AF_INET,
|
||||||
|
PeerAddr => $t_address,
|
||||||
|
PeerPort => $t_port,
|
||||||
|
LocalAddr => $t_bind_address,
|
||||||
|
Type => SOCK_STREAM
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
$t_socket = $SOCKET_MODULE->new (
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
Domain => AF_INET,
|
Domain => AF_INET,
|
||||||
PeerAddr => $t_address,
|
PeerAddr => $t_address,
|
||||||
|
@ -324,6 +372,7 @@ sub start_client {
|
||||||
Type => SOCK_STREAM
|
Type => SOCK_STREAM
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (! defined ($t_socket)) {
|
if (! defined ($t_socket)) {
|
||||||
error ("Cannot connect to $t_address on port $t_port: $!.");
|
error ("Cannot connect to $t_address on port $t_port: $!.");
|
||||||
|
@ -344,19 +393,39 @@ sub start_client_proxy {
|
||||||
|
|
||||||
# Connect to proxy
|
# Connect to proxy
|
||||||
if ($SOCKET_MODULE ne 'IO::Socket::INET') {
|
if ($SOCKET_MODULE ne 'IO::Socket::INET') {
|
||||||
|
if (defined ($t_bind_address)) {
|
||||||
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
|
Domain => AF_INET6,
|
||||||
|
PeerAddr => $t_proxy_address,
|
||||||
|
PeerPort => $t_proxy_port,
|
||||||
|
LocalAddr => $t_bind_address,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
$t_socket = $SOCKET_MODULE->new (
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
Domain => AF_INET6,
|
Domain => AF_INET6,
|
||||||
PeerAddr => $t_proxy_address,
|
PeerAddr => $t_proxy_address,
|
||||||
PeerPort => $t_proxy_port,
|
PeerPort => $t_proxy_port,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (! defined ($t_socket)) {
|
if (! defined ($t_socket)) {
|
||||||
|
if (defined ($t_bind_address)) {
|
||||||
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
|
Domain => AF_INET,
|
||||||
|
PeerAddr => $t_proxy_address,
|
||||||
|
PeerPort => $t_proxy_port,
|
||||||
|
LocalAddr => $t_bind_address,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
$t_socket = $SOCKET_MODULE->new (
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
Domain => AF_INET,
|
Domain => AF_INET,
|
||||||
PeerAddr => $t_proxy_address,
|
PeerAddr => $t_proxy_address,
|
||||||
PeerPort => $t_proxy_port,
|
PeerPort => $t_proxy_port,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (! defined ($t_socket)) {
|
if (! defined ($t_socket)) {
|
||||||
error ("Cannot connect to proxy server $t_proxy_address on port $t_proxy_port: $!.");
|
error ("Cannot connect to proxy server $t_proxy_address on port $t_proxy_port: $!.");
|
||||||
|
@ -408,6 +477,8 @@ sub start_ssl {
|
||||||
if ($t_ssl_cert eq ''){
|
if ($t_ssl_cert eq ''){
|
||||||
IO::Socket::SSL->start_SSL (
|
IO::Socket::SSL->start_SSL (
|
||||||
$t_socket,
|
$t_socket,
|
||||||
|
# No authentication
|
||||||
|
SSL_verify_mode => 0x00,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
elsif ($t_ssl_ca eq '') {
|
elsif ($t_ssl_ca eq '') {
|
||||||
|
@ -525,6 +596,46 @@ sub recv_file {
|
||||||
print_log ("Received file '$file'");
|
print_log ("Received file '$file'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## SUB zrecv_file
|
||||||
|
## Receive a compressed file from the server
|
||||||
|
################################################################################
|
||||||
|
sub zrecv_file {
|
||||||
|
my $data = '';
|
||||||
|
my $file = $_[0];
|
||||||
|
my $response;
|
||||||
|
my $size;
|
||||||
|
my $zdata = '';
|
||||||
|
|
||||||
|
# Request file
|
||||||
|
send_data ("ZRECV <$file>\n");
|
||||||
|
|
||||||
|
# Wait for server response
|
||||||
|
$response = recv_command ();
|
||||||
|
if ($response !~ /^ZRECV SIZE (\d+)$/) {
|
||||||
|
error ("Server responded $response.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$size = $1;
|
||||||
|
send_data ("ZRECV OK\n");
|
||||||
|
|
||||||
|
# Receive file
|
||||||
|
$zdata = recv_data_block ($size);
|
||||||
|
if (!unzip(\$zdata => \$data)) {
|
||||||
|
print_log ("Uncompress error: $UnzipError");
|
||||||
|
send_data ("ZRECV ERR\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Write it to disk
|
||||||
|
open (FILE, "> $file") || error ("Cannot open file '$file' for writing.");
|
||||||
|
binmode (FILE);
|
||||||
|
print (FILE $data);
|
||||||
|
close (FILE);
|
||||||
|
|
||||||
|
print_log ("Received compressed file '$file'");
|
||||||
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
## SUB send_file
|
## SUB send_file
|
||||||
## Send a file to the server
|
## Send a file to the server
|
||||||
|
@ -578,6 +689,55 @@ sub send_file {
|
||||||
print_log ("File sent");
|
print_log ("File sent");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## SUB zsend_file
|
||||||
|
## Send a file to the server (compressed)
|
||||||
|
################################################################################
|
||||||
|
sub zsend_file {
|
||||||
|
my $base_name;
|
||||||
|
my $data = '';
|
||||||
|
my $response = '';
|
||||||
|
my $retries;
|
||||||
|
my $file = $_[0];
|
||||||
|
my $size;
|
||||||
|
my $written;
|
||||||
|
|
||||||
|
# Read the file and compress its contents
|
||||||
|
if (! zip($file => \$data)) {
|
||||||
|
send_data ("QUIT\n");
|
||||||
|
error ("Compression error: $ZipError");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$size = length($data);
|
||||||
|
$base_name = basename ($file);
|
||||||
|
|
||||||
|
# Request to send file
|
||||||
|
send_data ("ZSEND <$base_name> SIZE $size\n");
|
||||||
|
print_log ("Request to send file '$base_name' size ${size}b (compressed)");
|
||||||
|
|
||||||
|
# Wait for server response
|
||||||
|
$response = recv_command ();
|
||||||
|
|
||||||
|
# Server rejected the file
|
||||||
|
if ($response ne "ZSEND OK") {
|
||||||
|
send_data ("QUIT\n");
|
||||||
|
error ("Server responded $response.");
|
||||||
|
}
|
||||||
|
|
||||||
|
print_log ("Server responded SEND OK");
|
||||||
|
send_data ($data);
|
||||||
|
|
||||||
|
# Wait for server response
|
||||||
|
$response = recv_command ();
|
||||||
|
if ($response ne "ZSEND OK") {
|
||||||
|
send_data ("QUIT\n");
|
||||||
|
error ("Server responded $response.");
|
||||||
|
}
|
||||||
|
|
||||||
|
print_log ("File sent");
|
||||||
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Common functions
|
# Common functions
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -830,15 +990,23 @@ if ($t_recv == 0) {
|
||||||
|
|
||||||
# Send the files
|
# Send the files
|
||||||
foreach $file (@ARGV) {
|
foreach $file (@ARGV) {
|
||||||
|
if ($t_zip == 1) {
|
||||||
|
zsend_file($file);
|
||||||
|
} else {
|
||||||
send_file ($file);
|
send_file ($file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
# Send the files
|
# Receive the files
|
||||||
foreach $file (@ARGV) {
|
foreach $file (@ARGV) {
|
||||||
|
if ($t_zip == 1) {
|
||||||
|
zrecv_file ($file);
|
||||||
|
} else {
|
||||||
recv_file ($file);
|
recv_file ($file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Tell the server that we are finished
|
# Tell the server that we are finished
|
||||||
send_data ("QUIT\n");
|
send_data ("QUIT\n");
|
||||||
|
@ -882,6 +1050,8 @@ __END__
|
||||||
|
|
||||||
=item I<-x pwd> B<Server password>.
|
=item I<-x pwd> B<Server password>.
|
||||||
|
|
||||||
|
=item I<-z> Compress data.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 EXIT STATUS
|
=head1 EXIT STATUS
|
||||||
|
|
|
@ -58,6 +58,8 @@ use strict;
|
||||||
use File::Basename;
|
use File::Basename;
|
||||||
use Getopt::Std;
|
use Getopt::Std;
|
||||||
use IO::Select;
|
use IO::Select;
|
||||||
|
use IO::Compress::Zip qw(zip $ZipError);
|
||||||
|
use IO::Uncompress::Unzip qw(unzip $UnzipError);
|
||||||
use Socket (qw(SOCK_STREAM AF_INET AF_INET6));
|
use Socket (qw(SOCK_STREAM AF_INET AF_INET6));
|
||||||
my $SOCKET_MODULE =
|
my $SOCKET_MODULE =
|
||||||
eval { require IO::Socket::INET6 } ? 'IO::Socket::INET6'
|
eval { require IO::Socket::INET6 } ? 'IO::Socket::INET6'
|
||||||
|
@ -131,6 +133,12 @@ my $t_ssl_pwd = '';
|
||||||
# Timeout for socket read/write operations in seconds
|
# Timeout for socket read/write operations in seconds
|
||||||
my $t_timeout = 1;
|
my $t_timeout = 1;
|
||||||
|
|
||||||
|
# bind ipaddr
|
||||||
|
my $t_bind_address = undef;
|
||||||
|
|
||||||
|
# Compress data before sending it through the socket.
|
||||||
|
my $t_zip = 0;
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
## SUB print_help
|
## SUB print_help
|
||||||
## Print help screen.
|
## Print help screen.
|
||||||
|
@ -141,6 +149,7 @@ sub print_help {
|
||||||
print ("Tentacle client v$VERSION. See http://www.openideas.info/wiki for protocol description.\n\n");
|
print ("Tentacle client v$VERSION. See http://www.openideas.info/wiki for protocol description.\n\n");
|
||||||
print ("Options:\n");
|
print ("Options:\n");
|
||||||
print ("\t-a address\tServer address (default $t_address).\n");
|
print ("\t-a address\tServer address (default $t_address).\n");
|
||||||
|
print ("\t-b localaddress\tLocal address to bind.\n");
|
||||||
print ("\t-c\t\tEnable SSL without a client certificate.\n");
|
print ("\t-c\t\tEnable SSL without a client certificate.\n");
|
||||||
print ("\t-e cert\t\tOpenSSL certificate file. Enables SSL.\n");
|
print ("\t-e cert\t\tOpenSSL certificate file. Enables SSL.\n");
|
||||||
print ("\t-f ca\t\tVerify that the peer certificate is signed by a ca.\n");
|
print ("\t-f ca\t\tVerify that the peer certificate is signed by a ca.\n");
|
||||||
|
@ -154,7 +163,8 @@ sub print_help {
|
||||||
print ("\t-v\t\tBe verbose.\n");
|
print ("\t-v\t\tBe verbose.\n");
|
||||||
print ("\t-w\t\tPrompt for OpenSSL private key password.\n");
|
print ("\t-w\t\tPrompt for OpenSSL private key password.\n");
|
||||||
print ("\t-x pwd\t\tServer password.\n");
|
print ("\t-x pwd\t\tServer password.\n");
|
||||||
print ("\t-y proxy\tProxy server string (user:password\@address:port).\n\n");
|
print ("\t-y proxy\tProxy server string (user:password\@address:port).\n");
|
||||||
|
print ("\t-z Compress data.\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -166,7 +176,7 @@ sub parse_options {
|
||||||
my $tmp;
|
my $tmp;
|
||||||
|
|
||||||
# Get options
|
# Get options
|
||||||
if (getopts ('a:ce:f:ghk:p:qr:t:vwx:y:', \%opts) == 0 || defined ($opts{'h'})) {
|
if (getopts ('a:b:ce:f:ghk:p:qr:t:vwx:y:z', \%opts) == 0 || defined ($opts{'h'})) {
|
||||||
print_help ();
|
print_help ();
|
||||||
exit 1;
|
exit 1;
|
||||||
}
|
}
|
||||||
|
@ -183,6 +193,18 @@ sub parse_options {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Bind local address
|
||||||
|
if (defined ($opts{'b'})) {
|
||||||
|
$t_bind_address = $opts{'b'};
|
||||||
|
if (($t_bind_address !~ /^[a-zA-Z\.][a-zA-Z0-9\.\-]+$/ && ($t_bind_address !~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
|
||||||
|
|| $1 < 0 || $1 > 255 || $2 < 0 || $2 > 255
|
||||||
|
|| $3 < 0 || $3 > 255 || $4 < 0 || $4 > 255)) &&
|
||||||
|
($t_address !~ /^[0-9a-f:]+$/o)) {
|
||||||
|
error ("Local address $t_bind_address is not valid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
# Enable SSL without a client certificate
|
# Enable SSL without a client certificate
|
||||||
if (defined ($opts{'c'})) {
|
if (defined ($opts{'c'})) {
|
||||||
require IO::Socket::SSL;
|
require IO::Socket::SSL;
|
||||||
|
@ -299,6 +321,11 @@ sub parse_options {
|
||||||
error ("Proxy port $t_proxy_port is not valid.");
|
error ("Proxy port $t_proxy_port is not valid.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Compress data
|
||||||
|
if (defined ($opts{'z'})) {
|
||||||
|
$t_zip = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -309,6 +336,16 @@ sub start_client {
|
||||||
|
|
||||||
# Connect to server
|
# Connect to server
|
||||||
if ($SOCKET_MODULE ne 'IO::Socket::INET') {
|
if ($SOCKET_MODULE ne 'IO::Socket::INET') {
|
||||||
|
if (defined ($t_bind_address)) {
|
||||||
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
|
Domain => AF_INET6,
|
||||||
|
PeerAddr => $t_address,
|
||||||
|
PeerPort => $t_port,
|
||||||
|
LocalAddr => $t_bind_address,
|
||||||
|
Type => SOCK_STREAM
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
$t_socket = $SOCKET_MODULE->new (
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
Domain => AF_INET6,
|
Domain => AF_INET6,
|
||||||
PeerAddr => $t_address,
|
PeerAddr => $t_address,
|
||||||
|
@ -316,7 +353,18 @@ sub start_client {
|
||||||
Type => SOCK_STREAM
|
Type => SOCK_STREAM
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (! defined ($t_socket)) {
|
if (! defined ($t_socket)) {
|
||||||
|
if (defined ($t_bind_address)) {
|
||||||
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
|
Domain => AF_INET,
|
||||||
|
PeerAddr => $t_address,
|
||||||
|
PeerPort => $t_port,
|
||||||
|
LocalAddr => $t_bind_address,
|
||||||
|
Type => SOCK_STREAM
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
$t_socket = $SOCKET_MODULE->new (
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
Domain => AF_INET,
|
Domain => AF_INET,
|
||||||
PeerAddr => $t_address,
|
PeerAddr => $t_address,
|
||||||
|
@ -324,6 +372,7 @@ sub start_client {
|
||||||
Type => SOCK_STREAM
|
Type => SOCK_STREAM
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (! defined ($t_socket)) {
|
if (! defined ($t_socket)) {
|
||||||
error ("Cannot connect to $t_address on port $t_port: $!.");
|
error ("Cannot connect to $t_address on port $t_port: $!.");
|
||||||
|
@ -344,19 +393,39 @@ sub start_client_proxy {
|
||||||
|
|
||||||
# Connect to proxy
|
# Connect to proxy
|
||||||
if ($SOCKET_MODULE ne 'IO::Socket::INET') {
|
if ($SOCKET_MODULE ne 'IO::Socket::INET') {
|
||||||
|
if (defined ($t_bind_address)) {
|
||||||
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
|
Domain => AF_INET6,
|
||||||
|
PeerAddr => $t_proxy_address,
|
||||||
|
PeerPort => $t_proxy_port,
|
||||||
|
LocalAddr => $t_bind_address,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
$t_socket = $SOCKET_MODULE->new (
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
Domain => AF_INET6,
|
Domain => AF_INET6,
|
||||||
PeerAddr => $t_proxy_address,
|
PeerAddr => $t_proxy_address,
|
||||||
PeerPort => $t_proxy_port,
|
PeerPort => $t_proxy_port,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (! defined ($t_socket)) {
|
if (! defined ($t_socket)) {
|
||||||
|
if (defined ($t_bind_address)) {
|
||||||
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
|
Domain => AF_INET,
|
||||||
|
PeerAddr => $t_proxy_address,
|
||||||
|
PeerPort => $t_proxy_port,
|
||||||
|
LocalAddr => $t_bind_address,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
$t_socket = $SOCKET_MODULE->new (
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
Domain => AF_INET,
|
Domain => AF_INET,
|
||||||
PeerAddr => $t_proxy_address,
|
PeerAddr => $t_proxy_address,
|
||||||
PeerPort => $t_proxy_port,
|
PeerPort => $t_proxy_port,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (! defined ($t_socket)) {
|
if (! defined ($t_socket)) {
|
||||||
error ("Cannot connect to proxy server $t_proxy_address on port $t_proxy_port: $!.");
|
error ("Cannot connect to proxy server $t_proxy_address on port $t_proxy_port: $!.");
|
||||||
|
@ -408,6 +477,8 @@ sub start_ssl {
|
||||||
if ($t_ssl_cert eq ''){
|
if ($t_ssl_cert eq ''){
|
||||||
IO::Socket::SSL->start_SSL (
|
IO::Socket::SSL->start_SSL (
|
||||||
$t_socket,
|
$t_socket,
|
||||||
|
# No authentication
|
||||||
|
SSL_verify_mode => 0x00,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
elsif ($t_ssl_ca eq '') {
|
elsif ($t_ssl_ca eq '') {
|
||||||
|
@ -525,6 +596,46 @@ sub recv_file {
|
||||||
print_log ("Received file '$file'");
|
print_log ("Received file '$file'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## SUB zrecv_file
|
||||||
|
## Receive a compressed file from the server
|
||||||
|
################################################################################
|
||||||
|
sub zrecv_file {
|
||||||
|
my $data = '';
|
||||||
|
my $file = $_[0];
|
||||||
|
my $response;
|
||||||
|
my $size;
|
||||||
|
my $zdata = '';
|
||||||
|
|
||||||
|
# Request file
|
||||||
|
send_data ("ZRECV <$file>\n");
|
||||||
|
|
||||||
|
# Wait for server response
|
||||||
|
$response = recv_command ();
|
||||||
|
if ($response !~ /^ZRECV SIZE (\d+)$/) {
|
||||||
|
error ("Server responded $response.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$size = $1;
|
||||||
|
send_data ("ZRECV OK\n");
|
||||||
|
|
||||||
|
# Receive file
|
||||||
|
$zdata = recv_data_block ($size);
|
||||||
|
if (!unzip(\$zdata => \$data)) {
|
||||||
|
print_log ("Uncompress error: $UnzipError");
|
||||||
|
send_data ("ZRECV ERR\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Write it to disk
|
||||||
|
open (FILE, "> $file") || error ("Cannot open file '$file' for writing.");
|
||||||
|
binmode (FILE);
|
||||||
|
print (FILE $data);
|
||||||
|
close (FILE);
|
||||||
|
|
||||||
|
print_log ("Received compressed file '$file'");
|
||||||
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
## SUB send_file
|
## SUB send_file
|
||||||
## Send a file to the server
|
## Send a file to the server
|
||||||
|
@ -578,6 +689,55 @@ sub send_file {
|
||||||
print_log ("File sent");
|
print_log ("File sent");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## SUB zsend_file
|
||||||
|
## Send a file to the server (compressed)
|
||||||
|
################################################################################
|
||||||
|
sub zsend_file {
|
||||||
|
my $base_name;
|
||||||
|
my $data = '';
|
||||||
|
my $response = '';
|
||||||
|
my $retries;
|
||||||
|
my $file = $_[0];
|
||||||
|
my $size;
|
||||||
|
my $written;
|
||||||
|
|
||||||
|
# Read the file and compress its contents
|
||||||
|
if (! zip($file => \$data)) {
|
||||||
|
send_data ("QUIT\n");
|
||||||
|
error ("Compression error: $ZipError");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$size = length($data);
|
||||||
|
$base_name = basename ($file);
|
||||||
|
|
||||||
|
# Request to send file
|
||||||
|
send_data ("ZSEND <$base_name> SIZE $size\n");
|
||||||
|
print_log ("Request to send file '$base_name' size ${size}b (compressed)");
|
||||||
|
|
||||||
|
# Wait for server response
|
||||||
|
$response = recv_command ();
|
||||||
|
|
||||||
|
# Server rejected the file
|
||||||
|
if ($response ne "ZSEND OK") {
|
||||||
|
send_data ("QUIT\n");
|
||||||
|
error ("Server responded $response.");
|
||||||
|
}
|
||||||
|
|
||||||
|
print_log ("Server responded SEND OK");
|
||||||
|
send_data ($data);
|
||||||
|
|
||||||
|
# Wait for server response
|
||||||
|
$response = recv_command ();
|
||||||
|
if ($response ne "ZSEND OK") {
|
||||||
|
send_data ("QUIT\n");
|
||||||
|
error ("Server responded $response.");
|
||||||
|
}
|
||||||
|
|
||||||
|
print_log ("File sent");
|
||||||
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Common functions
|
# Common functions
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -830,15 +990,23 @@ if ($t_recv == 0) {
|
||||||
|
|
||||||
# Send the files
|
# Send the files
|
||||||
foreach $file (@ARGV) {
|
foreach $file (@ARGV) {
|
||||||
|
if ($t_zip == 1) {
|
||||||
|
zsend_file($file);
|
||||||
|
} else {
|
||||||
send_file ($file);
|
send_file ($file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
# Send the files
|
# Receive the files
|
||||||
foreach $file (@ARGV) {
|
foreach $file (@ARGV) {
|
||||||
|
if ($t_zip == 1) {
|
||||||
|
zrecv_file ($file);
|
||||||
|
} else {
|
||||||
recv_file ($file);
|
recv_file ($file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Tell the server that we are finished
|
# Tell the server that we are finished
|
||||||
send_data ("QUIT\n");
|
send_data ("QUIT\n");
|
||||||
|
@ -882,6 +1050,8 @@ __END__
|
||||||
|
|
||||||
=item I<-x pwd> B<Server password>.
|
=item I<-x pwd> B<Server password>.
|
||||||
|
|
||||||
|
=item I<-z> Compress data.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 EXIT STATUS
|
=head1 EXIT STATUS
|
||||||
|
|
|
@ -58,6 +58,8 @@ use strict;
|
||||||
use File::Basename;
|
use File::Basename;
|
||||||
use Getopt::Std;
|
use Getopt::Std;
|
||||||
use IO::Select;
|
use IO::Select;
|
||||||
|
use IO::Compress::Zip qw(zip $ZipError);
|
||||||
|
use IO::Uncompress::Unzip qw(unzip $UnzipError);
|
||||||
use Socket (qw(SOCK_STREAM AF_INET AF_INET6));
|
use Socket (qw(SOCK_STREAM AF_INET AF_INET6));
|
||||||
my $SOCKET_MODULE =
|
my $SOCKET_MODULE =
|
||||||
eval { require IO::Socket::INET6 } ? 'IO::Socket::INET6'
|
eval { require IO::Socket::INET6 } ? 'IO::Socket::INET6'
|
||||||
|
@ -131,6 +133,12 @@ my $t_ssl_pwd = '';
|
||||||
# Timeout for socket read/write operations in seconds
|
# Timeout for socket read/write operations in seconds
|
||||||
my $t_timeout = 1;
|
my $t_timeout = 1;
|
||||||
|
|
||||||
|
# bind ipaddr
|
||||||
|
my $t_bind_address = undef;
|
||||||
|
|
||||||
|
# Compress data before sending it through the socket.
|
||||||
|
my $t_zip = 0;
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
## SUB print_help
|
## SUB print_help
|
||||||
## Print help screen.
|
## Print help screen.
|
||||||
|
@ -141,6 +149,7 @@ sub print_help {
|
||||||
print ("Tentacle client v$VERSION. See http://www.openideas.info/wiki for protocol description.\n\n");
|
print ("Tentacle client v$VERSION. See http://www.openideas.info/wiki for protocol description.\n\n");
|
||||||
print ("Options:\n");
|
print ("Options:\n");
|
||||||
print ("\t-a address\tServer address (default $t_address).\n");
|
print ("\t-a address\tServer address (default $t_address).\n");
|
||||||
|
print ("\t-b localaddress\tLocal address to bind.\n");
|
||||||
print ("\t-c\t\tEnable SSL without a client certificate.\n");
|
print ("\t-c\t\tEnable SSL without a client certificate.\n");
|
||||||
print ("\t-e cert\t\tOpenSSL certificate file. Enables SSL.\n");
|
print ("\t-e cert\t\tOpenSSL certificate file. Enables SSL.\n");
|
||||||
print ("\t-f ca\t\tVerify that the peer certificate is signed by a ca.\n");
|
print ("\t-f ca\t\tVerify that the peer certificate is signed by a ca.\n");
|
||||||
|
@ -154,7 +163,8 @@ sub print_help {
|
||||||
print ("\t-v\t\tBe verbose.\n");
|
print ("\t-v\t\tBe verbose.\n");
|
||||||
print ("\t-w\t\tPrompt for OpenSSL private key password.\n");
|
print ("\t-w\t\tPrompt for OpenSSL private key password.\n");
|
||||||
print ("\t-x pwd\t\tServer password.\n");
|
print ("\t-x pwd\t\tServer password.\n");
|
||||||
print ("\t-y proxy\tProxy server string (user:password\@address:port).\n\n");
|
print ("\t-y proxy\tProxy server string (user:password\@address:port).\n");
|
||||||
|
print ("\t-z Compress data.\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -166,7 +176,7 @@ sub parse_options {
|
||||||
my $tmp;
|
my $tmp;
|
||||||
|
|
||||||
# Get options
|
# Get options
|
||||||
if (getopts ('a:ce:f:ghk:p:qr:t:vwx:y:', \%opts) == 0 || defined ($opts{'h'})) {
|
if (getopts ('a:b:ce:f:ghk:p:qr:t:vwx:y:z', \%opts) == 0 || defined ($opts{'h'})) {
|
||||||
print_help ();
|
print_help ();
|
||||||
exit 1;
|
exit 1;
|
||||||
}
|
}
|
||||||
|
@ -183,6 +193,18 @@ sub parse_options {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Bind local address
|
||||||
|
if (defined ($opts{'b'})) {
|
||||||
|
$t_bind_address = $opts{'b'};
|
||||||
|
if (($t_bind_address !~ /^[a-zA-Z\.][a-zA-Z0-9\.\-]+$/ && ($t_bind_address !~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
|
||||||
|
|| $1 < 0 || $1 > 255 || $2 < 0 || $2 > 255
|
||||||
|
|| $3 < 0 || $3 > 255 || $4 < 0 || $4 > 255)) &&
|
||||||
|
($t_address !~ /^[0-9a-f:]+$/o)) {
|
||||||
|
error ("Local address $t_bind_address is not valid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
# Enable SSL without a client certificate
|
# Enable SSL without a client certificate
|
||||||
if (defined ($opts{'c'})) {
|
if (defined ($opts{'c'})) {
|
||||||
require IO::Socket::SSL;
|
require IO::Socket::SSL;
|
||||||
|
@ -299,6 +321,11 @@ sub parse_options {
|
||||||
error ("Proxy port $t_proxy_port is not valid.");
|
error ("Proxy port $t_proxy_port is not valid.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Compress data
|
||||||
|
if (defined ($opts{'z'})) {
|
||||||
|
$t_zip = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -309,6 +336,16 @@ sub start_client {
|
||||||
|
|
||||||
# Connect to server
|
# Connect to server
|
||||||
if ($SOCKET_MODULE ne 'IO::Socket::INET') {
|
if ($SOCKET_MODULE ne 'IO::Socket::INET') {
|
||||||
|
if (defined ($t_bind_address)) {
|
||||||
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
|
Domain => AF_INET6,
|
||||||
|
PeerAddr => $t_address,
|
||||||
|
PeerPort => $t_port,
|
||||||
|
LocalAddr => $t_bind_address,
|
||||||
|
Type => SOCK_STREAM
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
$t_socket = $SOCKET_MODULE->new (
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
Domain => AF_INET6,
|
Domain => AF_INET6,
|
||||||
PeerAddr => $t_address,
|
PeerAddr => $t_address,
|
||||||
|
@ -316,7 +353,18 @@ sub start_client {
|
||||||
Type => SOCK_STREAM
|
Type => SOCK_STREAM
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (! defined ($t_socket)) {
|
if (! defined ($t_socket)) {
|
||||||
|
if (defined ($t_bind_address)) {
|
||||||
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
|
Domain => AF_INET,
|
||||||
|
PeerAddr => $t_address,
|
||||||
|
PeerPort => $t_port,
|
||||||
|
LocalAddr => $t_bind_address,
|
||||||
|
Type => SOCK_STREAM
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
$t_socket = $SOCKET_MODULE->new (
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
Domain => AF_INET,
|
Domain => AF_INET,
|
||||||
PeerAddr => $t_address,
|
PeerAddr => $t_address,
|
||||||
|
@ -324,6 +372,7 @@ sub start_client {
|
||||||
Type => SOCK_STREAM
|
Type => SOCK_STREAM
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (! defined ($t_socket)) {
|
if (! defined ($t_socket)) {
|
||||||
error ("Cannot connect to $t_address on port $t_port: $!.");
|
error ("Cannot connect to $t_address on port $t_port: $!.");
|
||||||
|
@ -344,19 +393,39 @@ sub start_client_proxy {
|
||||||
|
|
||||||
# Connect to proxy
|
# Connect to proxy
|
||||||
if ($SOCKET_MODULE ne 'IO::Socket::INET') {
|
if ($SOCKET_MODULE ne 'IO::Socket::INET') {
|
||||||
|
if (defined ($t_bind_address)) {
|
||||||
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
|
Domain => AF_INET6,
|
||||||
|
PeerAddr => $t_proxy_address,
|
||||||
|
PeerPort => $t_proxy_port,
|
||||||
|
LocalAddr => $t_bind_address,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
$t_socket = $SOCKET_MODULE->new (
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
Domain => AF_INET6,
|
Domain => AF_INET6,
|
||||||
PeerAddr => $t_proxy_address,
|
PeerAddr => $t_proxy_address,
|
||||||
PeerPort => $t_proxy_port,
|
PeerPort => $t_proxy_port,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (! defined ($t_socket)) {
|
if (! defined ($t_socket)) {
|
||||||
|
if (defined ($t_bind_address)) {
|
||||||
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
|
Domain => AF_INET,
|
||||||
|
PeerAddr => $t_proxy_address,
|
||||||
|
PeerPort => $t_proxy_port,
|
||||||
|
LocalAddr => $t_bind_address,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
$t_socket = $SOCKET_MODULE->new (
|
$t_socket = $SOCKET_MODULE->new (
|
||||||
Domain => AF_INET,
|
Domain => AF_INET,
|
||||||
PeerAddr => $t_proxy_address,
|
PeerAddr => $t_proxy_address,
|
||||||
PeerPort => $t_proxy_port,
|
PeerPort => $t_proxy_port,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (! defined ($t_socket)) {
|
if (! defined ($t_socket)) {
|
||||||
error ("Cannot connect to proxy server $t_proxy_address on port $t_proxy_port: $!.");
|
error ("Cannot connect to proxy server $t_proxy_address on port $t_proxy_port: $!.");
|
||||||
|
@ -408,6 +477,8 @@ sub start_ssl {
|
||||||
if ($t_ssl_cert eq ''){
|
if ($t_ssl_cert eq ''){
|
||||||
IO::Socket::SSL->start_SSL (
|
IO::Socket::SSL->start_SSL (
|
||||||
$t_socket,
|
$t_socket,
|
||||||
|
# No authentication
|
||||||
|
SSL_verify_mode => 0x00,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
elsif ($t_ssl_ca eq '') {
|
elsif ($t_ssl_ca eq '') {
|
||||||
|
@ -525,6 +596,46 @@ sub recv_file {
|
||||||
print_log ("Received file '$file'");
|
print_log ("Received file '$file'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## SUB zrecv_file
|
||||||
|
## Receive a compressed file from the server
|
||||||
|
################################################################################
|
||||||
|
sub zrecv_file {
|
||||||
|
my $data = '';
|
||||||
|
my $file = $_[0];
|
||||||
|
my $response;
|
||||||
|
my $size;
|
||||||
|
my $zdata = '';
|
||||||
|
|
||||||
|
# Request file
|
||||||
|
send_data ("ZRECV <$file>\n");
|
||||||
|
|
||||||
|
# Wait for server response
|
||||||
|
$response = recv_command ();
|
||||||
|
if ($response !~ /^ZRECV SIZE (\d+)$/) {
|
||||||
|
error ("Server responded $response.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$size = $1;
|
||||||
|
send_data ("ZRECV OK\n");
|
||||||
|
|
||||||
|
# Receive file
|
||||||
|
$zdata = recv_data_block ($size);
|
||||||
|
if (!unzip(\$zdata => \$data)) {
|
||||||
|
print_log ("Uncompress error: $UnzipError");
|
||||||
|
send_data ("ZRECV ERR\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Write it to disk
|
||||||
|
open (FILE, "> $file") || error ("Cannot open file '$file' for writing.");
|
||||||
|
binmode (FILE);
|
||||||
|
print (FILE $data);
|
||||||
|
close (FILE);
|
||||||
|
|
||||||
|
print_log ("Received compressed file '$file'");
|
||||||
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
## SUB send_file
|
## SUB send_file
|
||||||
## Send a file to the server
|
## Send a file to the server
|
||||||
|
@ -578,6 +689,55 @@ sub send_file {
|
||||||
print_log ("File sent");
|
print_log ("File sent");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## SUB zsend_file
|
||||||
|
## Send a file to the server (compressed)
|
||||||
|
################################################################################
|
||||||
|
sub zsend_file {
|
||||||
|
my $base_name;
|
||||||
|
my $data = '';
|
||||||
|
my $response = '';
|
||||||
|
my $retries;
|
||||||
|
my $file = $_[0];
|
||||||
|
my $size;
|
||||||
|
my $written;
|
||||||
|
|
||||||
|
# Read the file and compress its contents
|
||||||
|
if (! zip($file => \$data)) {
|
||||||
|
send_data ("QUIT\n");
|
||||||
|
error ("Compression error: $ZipError");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$size = length($data);
|
||||||
|
$base_name = basename ($file);
|
||||||
|
|
||||||
|
# Request to send file
|
||||||
|
send_data ("ZSEND <$base_name> SIZE $size\n");
|
||||||
|
print_log ("Request to send file '$base_name' size ${size}b (compressed)");
|
||||||
|
|
||||||
|
# Wait for server response
|
||||||
|
$response = recv_command ();
|
||||||
|
|
||||||
|
# Server rejected the file
|
||||||
|
if ($response ne "ZSEND OK") {
|
||||||
|
send_data ("QUIT\n");
|
||||||
|
error ("Server responded $response.");
|
||||||
|
}
|
||||||
|
|
||||||
|
print_log ("Server responded SEND OK");
|
||||||
|
send_data ($data);
|
||||||
|
|
||||||
|
# Wait for server response
|
||||||
|
$response = recv_command ();
|
||||||
|
if ($response ne "ZSEND OK") {
|
||||||
|
send_data ("QUIT\n");
|
||||||
|
error ("Server responded $response.");
|
||||||
|
}
|
||||||
|
|
||||||
|
print_log ("File sent");
|
||||||
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Common functions
|
# Common functions
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -830,15 +990,23 @@ if ($t_recv == 0) {
|
||||||
|
|
||||||
# Send the files
|
# Send the files
|
||||||
foreach $file (@ARGV) {
|
foreach $file (@ARGV) {
|
||||||
|
if ($t_zip == 1) {
|
||||||
|
zsend_file($file);
|
||||||
|
} else {
|
||||||
send_file ($file);
|
send_file ($file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
# Send the files
|
# Receive the files
|
||||||
foreach $file (@ARGV) {
|
foreach $file (@ARGV) {
|
||||||
|
if ($t_zip == 1) {
|
||||||
|
zrecv_file ($file);
|
||||||
|
} else {
|
||||||
recv_file ($file);
|
recv_file ($file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Tell the server that we are finished
|
# Tell the server that we are finished
|
||||||
send_data ("QUIT\n");
|
send_data ("QUIT\n");
|
||||||
|
@ -882,6 +1050,8 @@ __END__
|
||||||
|
|
||||||
=item I<-x pwd> B<Server password>.
|
=item I<-x pwd> B<Server password>.
|
||||||
|
|
||||||
|
=item I<-z> Compress data.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 EXIT STATUS
|
=head1 EXIT STATUS
|
||||||
|
|
|
@ -60,6 +60,8 @@ use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Getopt::Std;
|
use Getopt::Std;
|
||||||
use IO::Select;
|
use IO::Select;
|
||||||
|
use IO::Compress::Zip qw(zip $ZipError);
|
||||||
|
use IO::Uncompress::Unzip qw(unzip $UnzipError);
|
||||||
use threads;
|
use threads;
|
||||||
use Thread::Semaphore;
|
use Thread::Semaphore;
|
||||||
use POSIX ":sys_wait_h";
|
use POSIX ":sys_wait_h";
|
||||||
|
@ -959,6 +961,15 @@ sub serve_connection {
|
||||||
print_info ("Request to receive file '$1' from " . $t_client_socket->sockhost ());
|
print_info ("Request to receive file '$1' from " . $t_client_socket->sockhost ());
|
||||||
send_file ($1);
|
send_file ($1);
|
||||||
}
|
}
|
||||||
|
elsif ($command =~ /^ZSEND <(.*)> SIZE (\d+)$/) {
|
||||||
|
print_info ("Request to send compressed file '$1' size ${2}b from " . $t_client_socket->sockhost ());
|
||||||
|
zrecv_file ($1, $2);
|
||||||
|
}
|
||||||
|
# Client wants to receive a file
|
||||||
|
elsif ($command =~ /^ZRECV <(.*)>$/) {
|
||||||
|
print_info ("Request to receive compressed file '$1' from " . $t_client_socket->sockhost ());
|
||||||
|
zsend_file ($1);
|
||||||
|
}
|
||||||
# Quit
|
# Quit
|
||||||
elsif ($command =~ /^QUIT$/) {
|
elsif ($command =~ /^QUIT$/) {
|
||||||
print_info ("Connection closed from " . $t_client_socket->sockhost ());
|
print_info ("Connection closed from " . $t_client_socket->sockhost ());
|
||||||
|
@ -1070,6 +1081,61 @@ sub recv_file {
|
||||||
print_info ("Received file '$base_name' size ${size}b from " . $t_client_socket->sockhost ());
|
print_info ("Received file '$base_name' size ${size}b from " . $t_client_socket->sockhost ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## SUB zrecv_file
|
||||||
|
## Receive a compressed file of size $_[1] and save it in $t_directory as $_[0].
|
||||||
|
################################################################################
|
||||||
|
sub zrecv_file {
|
||||||
|
my $base_name = $_[0];
|
||||||
|
my $data = '';
|
||||||
|
my $file;
|
||||||
|
my $size = $_[1];
|
||||||
|
my $zdata = '';
|
||||||
|
|
||||||
|
# Check file name
|
||||||
|
if ($base_name =~ /[$t_invalid_chars]/) {
|
||||||
|
print_log ("File '$base_name' size ${size}b from " . $t_client_socket->sockhost () . " has an invalid file name");
|
||||||
|
send_data ("ZSEND ERR (invalid file name)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check file size, empty files are not allowed
|
||||||
|
if ($size < 1 || $size > $t_max_size) {
|
||||||
|
print_log ("File '$base_name' size ${size}b from " . $t_client_socket->sockhost () . " is too big");
|
||||||
|
send_data ("ZSEND ERR (file is too big)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Apply filters
|
||||||
|
$file = "$t_directory/" . apply_filters ($base_name) . $base_name;
|
||||||
|
|
||||||
|
# Check if file exists
|
||||||
|
if (-f $file && $t_overwrite == 0) {
|
||||||
|
print_log ("File '$base_name' size ${size}b from " . $t_client_socket->sockhost () . " already exists");
|
||||||
|
send_data ("ZSEND ERR (file already exists)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_data ("ZSEND OK\n");
|
||||||
|
|
||||||
|
# Receive file
|
||||||
|
$zdata = recv_data_block ($size);
|
||||||
|
if (!unzip(\$zdata => \$data)) {
|
||||||
|
print_log ("Uncompress error: $UnzipError");
|
||||||
|
send_data ("ZSEND ERR\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Write it to disk
|
||||||
|
open (FILE, "> $file") || error ("Cannot open file '$file' for writing.");
|
||||||
|
binmode (FILE);
|
||||||
|
print (FILE $data);
|
||||||
|
close (FILE);
|
||||||
|
|
||||||
|
send_data ("ZSEND OK\n");
|
||||||
|
print_info ("Received compressed file '$base_name' size ${size}b from " . $t_client_socket->sockhost ());
|
||||||
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
## SUB send_file
|
## SUB send_file
|
||||||
## Send a file to the client
|
## Send a file to the client
|
||||||
|
@ -1122,6 +1188,57 @@ sub send_file {
|
||||||
print_log ("Requested file '$file' from " . $t_client_socket->sockhost () . " sent");
|
print_log ("Requested file '$file' from " . $t_client_socket->sockhost () . " sent");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## SUB zsend_file
|
||||||
|
## Send a file to the client
|
||||||
|
################################################################################
|
||||||
|
sub zsend_file {
|
||||||
|
my $base_name = $_[0];
|
||||||
|
my $data = '';
|
||||||
|
my $file;
|
||||||
|
my $response;
|
||||||
|
my $size;
|
||||||
|
|
||||||
|
# Check file name
|
||||||
|
if ($base_name =~ /[$t_invalid_chars]/) {
|
||||||
|
print_log ("Requested compressed file '$base_name' from " . $t_client_socket->sockhost () . " has an invalid file name");
|
||||||
|
send_data ("ZRECV ERR (file has an invalid file name)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Apply filters
|
||||||
|
$file = "$t_directory/" . apply_filters ($base_name) . $base_name;
|
||||||
|
|
||||||
|
# Check if file exists
|
||||||
|
if (! -f $file) {
|
||||||
|
print_log ("Requested compressed '$file' from " . $t_client_socket->sockhost () . " does not exist");
|
||||||
|
send_data ("ZRECV ERR (file does not exist)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Read the file and compress its contents
|
||||||
|
if (! zip($file => \$data)) {
|
||||||
|
send_data ("QUIT\n");
|
||||||
|
error ("Compression error: $ZipError");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$size = length($data);
|
||||||
|
send_data ("ZRECV SIZE $size\n");
|
||||||
|
|
||||||
|
# Wait for client response
|
||||||
|
$response = recv_command ($t_block_size);
|
||||||
|
if ($response ne "ZRECV OK") {
|
||||||
|
print_log ("Requested compressed '$file' from " . $t_client_socket->sockhost () . " not sent");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Send the file
|
||||||
|
send_data ($data);
|
||||||
|
|
||||||
|
print_log ("Requested compressed '$file' from " . $t_client_socket->sockhost () . " sent");
|
||||||
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Common functions
|
# Common functions
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -60,6 +60,8 @@ use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Getopt::Std;
|
use Getopt::Std;
|
||||||
use IO::Select;
|
use IO::Select;
|
||||||
|
use IO::Compress::Zip qw(zip $ZipError);
|
||||||
|
use IO::Uncompress::Unzip qw(unzip $UnzipError);
|
||||||
use threads;
|
use threads;
|
||||||
use Thread::Semaphore;
|
use Thread::Semaphore;
|
||||||
use POSIX ":sys_wait_h";
|
use POSIX ":sys_wait_h";
|
||||||
|
@ -959,6 +961,15 @@ sub serve_connection {
|
||||||
print_info ("Request to receive file '$1' from " . $t_client_socket->sockhost ());
|
print_info ("Request to receive file '$1' from " . $t_client_socket->sockhost ());
|
||||||
send_file ($1);
|
send_file ($1);
|
||||||
}
|
}
|
||||||
|
elsif ($command =~ /^ZSEND <(.*)> SIZE (\d+)$/) {
|
||||||
|
print_info ("Request to send compressed file '$1' size ${2}b from " . $t_client_socket->sockhost ());
|
||||||
|
zrecv_file ($1, $2);
|
||||||
|
}
|
||||||
|
# Client wants to receive a file
|
||||||
|
elsif ($command =~ /^ZRECV <(.*)>$/) {
|
||||||
|
print_info ("Request to receive compressed file '$1' from " . $t_client_socket->sockhost ());
|
||||||
|
zsend_file ($1);
|
||||||
|
}
|
||||||
# Quit
|
# Quit
|
||||||
elsif ($command =~ /^QUIT$/) {
|
elsif ($command =~ /^QUIT$/) {
|
||||||
print_info ("Connection closed from " . $t_client_socket->sockhost ());
|
print_info ("Connection closed from " . $t_client_socket->sockhost ());
|
||||||
|
@ -1070,6 +1081,61 @@ sub recv_file {
|
||||||
print_info ("Received file '$base_name' size ${size}b from " . $t_client_socket->sockhost ());
|
print_info ("Received file '$base_name' size ${size}b from " . $t_client_socket->sockhost ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## SUB zrecv_file
|
||||||
|
## Receive a compressed file of size $_[1] and save it in $t_directory as $_[0].
|
||||||
|
################################################################################
|
||||||
|
sub zrecv_file {
|
||||||
|
my $base_name = $_[0];
|
||||||
|
my $data = '';
|
||||||
|
my $file;
|
||||||
|
my $size = $_[1];
|
||||||
|
my $zdata = '';
|
||||||
|
|
||||||
|
# Check file name
|
||||||
|
if ($base_name =~ /[$t_invalid_chars]/) {
|
||||||
|
print_log ("File '$base_name' size ${size}b from " . $t_client_socket->sockhost () . " has an invalid file name");
|
||||||
|
send_data ("ZSEND ERR (invalid file name)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check file size, empty files are not allowed
|
||||||
|
if ($size < 1 || $size > $t_max_size) {
|
||||||
|
print_log ("File '$base_name' size ${size}b from " . $t_client_socket->sockhost () . " is too big");
|
||||||
|
send_data ("ZSEND ERR (file is too big)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Apply filters
|
||||||
|
$file = "$t_directory/" . apply_filters ($base_name) . $base_name;
|
||||||
|
|
||||||
|
# Check if file exists
|
||||||
|
if (-f $file && $t_overwrite == 0) {
|
||||||
|
print_log ("File '$base_name' size ${size}b from " . $t_client_socket->sockhost () . " already exists");
|
||||||
|
send_data ("ZSEND ERR (file already exists)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_data ("ZSEND OK\n");
|
||||||
|
|
||||||
|
# Receive file
|
||||||
|
$zdata = recv_data_block ($size);
|
||||||
|
if (!unzip(\$zdata => \$data)) {
|
||||||
|
print_log ("Uncompress error: $UnzipError");
|
||||||
|
send_data ("ZSEND ERR\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Write it to disk
|
||||||
|
open (FILE, "> $file") || error ("Cannot open file '$file' for writing.");
|
||||||
|
binmode (FILE);
|
||||||
|
print (FILE $data);
|
||||||
|
close (FILE);
|
||||||
|
|
||||||
|
send_data ("ZSEND OK\n");
|
||||||
|
print_info ("Received compressed file '$base_name' size ${size}b from " . $t_client_socket->sockhost ());
|
||||||
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
## SUB send_file
|
## SUB send_file
|
||||||
## Send a file to the client
|
## Send a file to the client
|
||||||
|
@ -1122,6 +1188,57 @@ sub send_file {
|
||||||
print_log ("Requested file '$file' from " . $t_client_socket->sockhost () . " sent");
|
print_log ("Requested file '$file' from " . $t_client_socket->sockhost () . " sent");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## SUB zsend_file
|
||||||
|
## Send a file to the client
|
||||||
|
################################################################################
|
||||||
|
sub zsend_file {
|
||||||
|
my $base_name = $_[0];
|
||||||
|
my $data = '';
|
||||||
|
my $file;
|
||||||
|
my $response;
|
||||||
|
my $size;
|
||||||
|
|
||||||
|
# Check file name
|
||||||
|
if ($base_name =~ /[$t_invalid_chars]/) {
|
||||||
|
print_log ("Requested compressed file '$base_name' from " . $t_client_socket->sockhost () . " has an invalid file name");
|
||||||
|
send_data ("ZRECV ERR (file has an invalid file name)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Apply filters
|
||||||
|
$file = "$t_directory/" . apply_filters ($base_name) . $base_name;
|
||||||
|
|
||||||
|
# Check if file exists
|
||||||
|
if (! -f $file) {
|
||||||
|
print_log ("Requested compressed '$file' from " . $t_client_socket->sockhost () . " does not exist");
|
||||||
|
send_data ("ZRECV ERR (file does not exist)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Read the file and compress its contents
|
||||||
|
if (! zip($file => \$data)) {
|
||||||
|
send_data ("QUIT\n");
|
||||||
|
error ("Compression error: $ZipError");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$size = length($data);
|
||||||
|
send_data ("ZRECV SIZE $size\n");
|
||||||
|
|
||||||
|
# Wait for client response
|
||||||
|
$response = recv_command ($t_block_size);
|
||||||
|
if ($response ne "ZRECV OK") {
|
||||||
|
print_log ("Requested compressed '$file' from " . $t_client_socket->sockhost () . " not sent");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Send the file
|
||||||
|
send_data ($data);
|
||||||
|
|
||||||
|
print_log ("Requested compressed '$file' from " . $t_client_socket->sockhost () . " sent");
|
||||||
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Common functions
|
# Common functions
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
Loading…
Reference in New Issue