Sock Server and Client - perl

I have the following Socks Server
my $socks_server = IO::Socket::Socks->new(
ProxyAddr => "localhost",
ProxyPort => 8000,
Listen => 1,
) or die "socket error";
while(1) {
my $client = $socks_server->accept();
print $client;
unless ($client) {
print "ERROR:";
next;
}
}
and the following Socks Client
use strict;
use warnings;
use IO::Socket::Socks;
my $socks_client = IO::Socket::Socks->new(
ProxyAddr => "localhost",
ProxyPort => "8000",
) or die $SOCKS_ERROR;
print $socks_client "foo\n";
$socks_client->close();
the Socks client print "foo\n" , how can I let the Socks Server print it to the console when its received?

Following code is provided for demonstration purpose only, authentication is turned off for simplicity.
The code is based on documetation for IO::Socket::Socks
Code for server.pl
use strict;
use warnings;
use feature 'say';
use IO::Socket::Socks ':constants';
my $SOCKS_ERROR = 'Error: SOCKS';
my $socks_server = IO::Socket::Socks->new(
ProxyAddr => "localhost",
ProxyPort => 8000,
Listen => 1,
UserAuth => \&auth,
RequireAuth => 0
) or die $SOCKS_ERROR;
while(1) {
my $client = $socks_server->accept();
unless ($client) {
print "ERROR: $SOCKS_ERROR\n";
next;
}
my $command = $client->command();
if ($command->[0] == CMD_CONNECT) {
# Handle the CONNECT
$client->command_reply(REPLY_SUCCESS, 'localhost', 8000);
}
print while <$client>;
$client->close();
}
sub auth {
my ($user, $pass) = #_;
return 1 if $user eq "foo" && $pass eq "bar";
return 0;
}
Code for client.pl
use strict;
use warnings;
use feature 'say';
use IO::Socket::Socks;
my $socks_client = IO::Socket::Socks->new(
ProxyAddr => "localhost",
ProxyPort => "8000",
ConnectAddr => "localhost",
ConnectPort => "8022",
) or die $SOCKS_ERROR;
print $socks_client $_ for <DATA>;
$socks_client->close();
__DATA__
-----------------------------------------------
This a test message sent from remote client for
SOCKS demonstration code.
Enjoy your day.
Output on server.pl side
C:\....\examples\socks_server.pl
-----------------------------------------------
This a test message sent from remote client for
SOCKS demonstration code.
Enjoy your day.
Output on client.pl side
C:\...\examples\socks_client.pl
C:\...>

Related

How to write a client program for Net::WebSocket::Server program?

I have a server program that listens on 9000 port. But I can't find a way to write a client program for that server that connects server at 9000 port. Here is the main part of server program:
use strict;
use warnings;
use Net::WebSocket::Server;
my $port = "9000";
my $msg_count = 0;
print "starting server on $port \n\n";
my $count = 2400;
Net::WebSocket::Server->new(
listen => $port,
silence_max => 5,
tick_period => 300,
on_tick => sub {
my ($serv) = #_;
print "connections >> " . $serv->connections . "\n";
print $_->ip() for( $serv->connections() ); print "\n";
print $_->port() for( $serv->connections() ); print "\n\n";
$count++;
},
on_connect => sub {
my ($serv, $conn) = #_;
$conn->on(
handshake => sub {
my ($conn, $handshake) = #_;
my $tmp = $handshake->req->origin;
print "here ... $tmp \n\n";
},
utf8 => sub {
my ($conn, $msg) = #_;
my $IP = $conn->ip();
my $PORT = $conn->port();
my $SERVER = $conn->server();
my $SOCKET = $conn->socket();
my $str = Dumper $SOCKET;
I searched internet and what that sounds understandable to me is the following client program:
use strict;
use warnings;
use IO::Socket::SSL;
my $cl=IO::Socket::SSL->new("http://localhost:9000") or die "error=$!, ssl_error=$SSL_ERROR";
if($cl) {
$cl->connect_SSL or die $#;
# Something about certificates?
$cl->syswrite("Command");
close($cl);
}
But its not working. The error client program generates is as follows:
Expected 'PeerService' at client2.pl line 5.
I am newbie in Socket programming and currently understanding websockets programming in Perl.
Note: I am on windows platform.
I ran the example code suggested https://stackoverflow.com/questions/37318581/simple-perl-websocket-client. It gives error "Can't use an undefined value as a subroutine reference at C:/Strawberry/perl/site/lib/Protocol/WebSocket/Client.pm line 103.":
use strict;
use warnings;
use Protocol::WebSocket::Client;
my $client = Protocol::WebSocket::Client->new(url => 'ws://localhost:9000') or die "$!";
my $reply = "Free\n";
# Sends a correct handshake header
$client->connect or die "$!";
# Register on connect handler
$client->on(
connect => sub {
$client->write('hi there');
}
) or die "$!";
# Parses incoming data and on every frame calls on_read
$client->read($reply);
print "$reply\n";
# Sends correct close header
$client->disconnect;
Please investigate following demo code snippets for WebSocket Server and Client.
Note: please do not forget to alter code to match your server origin (ip address and port)
use strict;
use warnings;
use feature 'say';
use Net::WebSocket::Server;
my $origin = 'http://192.168.1.160:8080'; # server origin
my $port = 8080;
$| = 1;
say "Starting server on $port";
Net::WebSocket::Server->new(
listen => $port,
tick_period => 60,
on_tick => sub {
my ($serv) = #_;
my $stamp = 'Server time: ' . scalar localtime;
$_->send_utf8($stamp) for $serv->connections;
},
on_connect => sub {
my ($serv, $conn) = #_;
$conn->on(
handshake => sub {
my ($conn, $handshake) = #_;
$conn->disconnect() unless $handshake->req->origin eq $origin;
},
ready => sub {
my ($conn) = #_;
say "Client: connect IP $conn->{ip} PORT $conn->{port}";
my $msg = 'Connected server time is ' . scalar localtime . "\n";
$_->send_utf8($msg) for $conn->server->connections;
},
utf8 => sub {
my ($conn, $msg) = #_;
say "Client message: $conn->{ip} $msg";
$_->send_utf8('Server reply: ' . $msg)
for $conn->server->connections;
$conn->disconnect() if $msg eq 'exit';
},
binary => sub {
my ($conn, $msg) = #_;
$_->send_binary($msg) for $conn->server->connections;
},
pong => sub {
my ($conn, $msg) = #_;
$_->send_utf8($msg) for $conn->server->connections;
},
disconnect => sub {
my ($conn, $code, $reason) = #_;
say "Client: disconnect IP $conn->{ip} PORT $conn->{port}";
},
);
},
)->start;
Client
use strict;
use warnings;
use feature 'say';
use IO::Async::Loop;
use Net::Async::WebSocket::Client;
my $HOST = '192.168.1.160';
my $PORT = 8080;
my $loop = IO::Async::Loop->new;
my $client = Net::Async::WebSocket::Client->new(
on_text_frame => sub {
my ( $self, $frame ) = #_;
say $frame;
},
);
my $input = IO::Async::Stream->new_for_stdin(
on_read => sub {
my ( $self, $buffref, $eof ) = #_;
my $msg;
$msg = $1 while $$buffref =~ s/^(.*)\n//;
$client->send_text_frame( $msg );
$loop->loop_stop if $msg eq 'exit';
return 0;
},
);
$loop->add( $client );
$loop->add( $input );
$client->connect(
url => "ws://$HOST:$PORT/"
)->then( sub {
say 'Successfully connected to server';
$client->send_text_frame( scalar localtime );
})->get;
$loop->run;
say 'Bye, until next time';
exit 0;
References:
Net::WebSocket::Server
Net::Async::WebSocket::Client
IO::Async::Loop

How to set in PERL recv timeout in my code?

I want to set timeout in my recv function in this specific code below, because sometimes my script stuck forever. I am new in socket programming so i would really appreciate any help. Thanks in advance.
use IO::Socket::INET;
use IO::Select;
use LWP::UserAgent;
use JSON::XS 'decode_json';
use Data::Dumper;
use DBI();
sub dbconn {
my $db_conf = shift;
my $dbh = DBI->connect("DBI:Pg:dbname=somedatabase;host=somehost", "postgres", "",
{pg_server_prepare =>
0,AutoCommit => 1,RaiseError=>1});
$dbh->do("SET CLIENT_ENCODING TO 'UTF-8';");
return $dbh;
}
# auto-flush on socket
$| = 1;
# creating a listening socket
my $socket = new IO::Socket::INET (
LocalHost => '0.0.0.0',
LocalPort => '5000',
Proto => 'tcp',
Listen => 5,
Reuse => 1
);
die "cannot create socket $!\n" unless $socket;
$sel = IO::Select->new( $socket );
print "Server waiting for client connection on port 5000...\n";
my $command = 1;
my $watchTracker = "*HQ,";
my $tl206 = ",LAT:";
my $watchConnectedCheck = ",A,";
my $gpsType;
my $circleString = ",LINK,";
my $dataToSend;
my $new;
my $dbh = dbconn();
while(#ready = $sel->can_read) {
foreach $fh (#ready) {
if($fh == $socket) {
# Create a new socket
$new = $socket->accept;
$new->recv($dataReceived, 1024);
$new->recv($dataReceived, 1024);
# get information about a newly connected client
my $client_address = $new->peerhost();
my $client_port = $new->peerport();
print "===============================================\n";
print "===============================================\n\n";
print "Connection from $client_address:$client_port\n";
print "General data received: $dataReceived\n\n";
#MORE LINES...
}
else {
# Process socket
# Maybe we have finished with the socket
$sel->remove($fh);
$fh->close;
}
}
}
$dbh->disconnect();
Perhaps I am misunderstanding the question, but have you tried setting a timeout in the socket with "Timeout"?
See IO::Socket::INET.
EDIT: I did not catch the 'recv' bit. You have to use setsockopt, which is not wholly portable, so the final answer is somewhat dependent on your platform. Here are some posts that may help:
How do I set `SO_RCVTIMEO` on a socket in Perl?
http://www.perlmonks.org/?node_id=761935
E.g.,
$socket->setsockopt(SOL_SOCKET, SO_RCVTIMEO, pack('l!l!', 30, 0))
or die "setsockopt: $!";

Perl IO::Async parallel tcp connections

I've got a problem that I can't easily find the solution to for some reason.
I try to build multiple parallel TCP connections to a server via IO::Async.
My goal is to run TCP connections in parallel. The connections do not need to communicate between themselves but I need to catch and save output of them in a hash.
The following code is an example with a single connection.
#!/usr/bin/perl
use strict;
use warnings;
use IO::Async::Loop;
use IO::Async::Stream;
my $CRLF = "\x0d\x0a"; # because \r\n is not portable
my $HOST = shift #ARGV or die "Need HOST";
my $PORT = shift #ARGV or die "Need PORT";
my $loop = IO::Async::Loop->new;
my $socket;
$loop->connect(
host => $HOST,
service => $PORT,
socktype => 'stream',
on_connected => sub { $socket = shift },
on_resolve_error => sub { die "Cannot resolve - $_[0]\n" },
on_connect_error => sub { die "Cannot connect\n" },
);
$loop->loop_once until defined $socket;
# $socket is just an IO::Socket reference
my $peeraddr = $socket->peerhost . ":" . $socket->peerport;
print STDERR "Connected to $peeraddr\n";
# We need to create a cross-connected pair of Streams. Can't do that
# easily without a temporary variable
my ( $socketstream, $stdiostream );
$socketstream = IO::Async::Stream->new(
handle => $socket,
on_read => sub {
my ( undef, $buffref, $eof ) = #_;
while( $$buffref =~ s/^(.*)$CRLF// ) {
$stdiostream->write( $1 . "\n" );
}
return 0;
},
on_closed => sub {
print STDERR "Closed connection to $peeraddr\n";
$stdiostream->close_when_empty;
},
);
$loop->add( $socketstream );
$stdiostream = IO::Async::Stream->new_for_stdio(
on_read => sub {
my ( undef, $buffref, $eof ) = #_;
while( $$buffref =~ s/^(.*)\n// ) {
$socketstream->write( $1 . $CRLF );
}
return 0;
},
on_closed => sub {
$socketstream->close_when_empty;
},
);
$loop->add( $stdiostream );
$loop->await_all( $socketstream->new_close_future, $stdiostream->new_close_future );
How could I modify this code to handle an IP list as asynchronous connections and store output in a dedicated hash?
Finally maybe to limit max parallel connection to 100.
Any ideas?

Perl Socket Conditional doesn't work

I'm trying to create a server and client wherein the server returns a diferent message to the client according to what client sends. If the client makes the connection but sends nothing, the server will return message 1 and in case the client sends some data, the server will return message 2. But this doesn't work, the client stays waiting the data and nothing prints.
Client:
use IO::Socket;
my $sock = new IO::Socket::INET (
PeerAddr => '10.1.1.28',
PeerPort => '7070',
Proto => 'tcp' );
if (#ARGV != "") {
print $sock "$ARGV[0] $ARGV[1]";
} else {
$data = <$sock>;
print $data;
}
$sock->close;
Server
use IO::Socket;
my $sock = new IO::Socket::INET (
LocalHost => '10.1.1.28',
LocalPort => '7070',
Proto => 'tcp',
Listen => '1',
);
while(1) {
my $new_sock = $sock->accept();
if (<$new_sock> ne "") {
print $new_sock "conection with parameters";
} else {
print $new_sock "default message";
};
Need to chomp
use IO::Socket;
use Data::Dumper;
my $sock = new IO::Socket::INET(
LocalPort => '7070',
Proto => 'tcp',
Listen => '1',
);
while (1) {
my $new_sock = $sock->accept();
my $in = <$new_sock>;
chomp($in);
if ( $in ne "" ) {
print Dumper($in);
print $new_sock "conection with parameters";
}
else {
print $new_sock "default message";
}
}

Perl: How to get IO::Socket::INET timeout after X seconds?

I'm trying to connect to some host, using invalid port, and i want to get timeout after X seconds. How to do that ?
My code:
$sock = new IO::Socket::INET(
PeerAddr => $_[0],
PeerPort => $_[1],
Proto => 'tcp',
Timeout => 2
);
If you check the code you'll see (I copied it from my Ubuntu 10.04) :
my $timeout = ${*$sock}{'io_socket_timeout'};
# my $before = time() if $timeout;
undef $#;
if ($sock->connect(pack_sockaddr_in($rport, $raddr))) {
# ${*$sock}{'io_socket_timeout'} = $timeout;
return $sock;
}
return _error($sock, $!, $# || "Timeout")
unless #raddr;
# if ($timeout) {
# my $new_timeout = $timeout - (time() - $before);
# return _error($sock,
# (exists(&Errno::ETIMEDOUT) ? Errno::ETIMEDOUT() : $EINVAL),
# "Timeout") if $new_timeout <= 0;
# ${*$sock}{'io_socket_timeout'} = $new_timeout;
# }
Apparently the timeout stuff is commented out so that expleins why it is ignored.
I found a post dating from 2003 where this was discussed. One suggestion (at the bottom) was to open the socket in an eval block which gets terminated by an alarm signal :
eval {
local $SIG{ALRM} = sub { die 'Timed Out'; };
alarm 3;
my $sock = IO::Socket::INET->new(
PeerAddr => inet_ntoa( gethostbyname($host) ),
PeerPort => 'whois',
Proto => 'tcp',
## timeout => ,
);
$sock->autoflush;
print $sock "$qry\015\012";
undef $/; $data = <$sock>; $/ = "\n";
alarm 0;
};
alarm 0; # race condition protection
return "Error: timeout." if ( $# && $# =~ /Timed Out/ );
return "Error: Eval corrupted: $#" if $#;
Not very elegant, but if it works...
Let's verify with a slow server and impatient client :
# Impatient Client
use IO::Socket::INET;
$sock = new IO::Socket::INET(
PeerAddr => "localhost",
PeerPort => "10007",
Proto => 'tcp',
Timeout => 2,
);
print <$sock>;
close($sock);
# SlowServer
use IO::Socket::INET;
$sock = new IO::Socket::INET(
LocalAddr => "localhost",
LocalPort => "10007",
Proto => 'tcp',
Listen => 1,
Reuse => 1,
);
$newsock = $sock->accept();
sleep 5;
#while (<$newsock>) {
# print $_;
#}
print $newsock "Some Stuff";
close($newsock);
close($sock);
if we run this:
pti#pti-laptop:~/playpen$ perl server.pl&
[1] 9130
pti#pti-laptop:~/playpen$ time perl test.pl
Some Stuff[1]+ Done perl server.pl
real 0m5.039s
user 0m0.050s
sys 0m0.030s
So it ignores the 2 second timeout and runs for the full 5 seconds.
Now the other impatient client :
use IO::Socket::INET;
eval {
local $SIG{ALRM} = sub { die 'Timed Out'; };
alarm 2;
$sock = new IO::Socket::INET(
PeerAddr => "localhost",
PeerPort => "10007",
Proto => 'tcp',
Timeout => 2,
);
print <$sock>;
close($sock);
alarm 0;
};
alarm 0; # race condition protection
print "Error: timeout." if ( $# && $# =~ /Timed Out/ );
print "Error: Eval corrupted: $#" if $#;
~
and running it :
pti#pti-laptop:~/playpen$ perl server.pl&
[1] 9175
pti#pti-laptop:~/playpen$ time perl test2.pl
Error: timeout.Error: Eval corrupted: Timed Out at test2.pl line 3.
real 0m2.040s
user 0m0.020s
sys 0m0.010s
Yep, this timeouts after 2 seconds as expected.
So much easier is to use the
IO::Socket::Timeout
as per below and it works like a charm.
use IO::Socket::Timeout;
my $socket = IO::Socket::INET->new( Timeout => 2 );
IO::Socket::Timeout->enable_timeouts_on($socket);
$socket->read_timeout(0.5); # These will work
$socket->write_timeout(0.5); # These will work