Perl client/server socket - perl

--|proxy|--|mux|--|demux|--|proxy|--
--
--
--
machineA satellite link machineB
172.16.1.224 172.16.1.218
Greetings,
I have setup as above. I'm trying to create 'mux'. Basically, it reads traffic from a proxy and splits it up for transmission over 4 wires. The 'demux' reads off 4 wires and forwards traffic on to the proxy.
I've got a basic client/server setup in Perl. But I don't know how to get traffic from the proxy into 'mux'?
Here is my code:
server.pl -- runs on 172.16.1.218
use IO::Socket;
$| = 1;
$socket = new IO::Socket::INET (
LocalHost => '172.16.1.218',
LocalPort => '5000',
Proto => 'tcp',
Listen => 5,
Reuse => 1
);
die "Coudn't open socket" unless $socket;
print "\nTCPServer Waiting for client on port 5000";
while(1)
{
$client_socket = "";
$client_socket = $socket->accept();
$peer_address = $client_socket->peerhost();
$peer_port = $client_socket->peerport();
#print "\n I got a connection from ( $peer_address , $peer_port ) ";
while (1){
$send_data = <STDIN>;
$client_socket->send($send_data);
$client_socket->recv($recieved_data,10);
print $recieved_data;#."\n";
#$client_socket->autoflush();
}
}
and:
client.pl
use IO::Socket;
$socket = new IO::Socket::INET (
PeerAddr => '172.16.1.224',
PeerPort => 5000,
Proto => 'tcp',
)
or die "Couldn't connect to Server\n";
while (1) {
$socket->recv($recv_data,10);
print $recv_data."\n";
$send_data = <STDIN>;
$socket->send($send_data);
}
I'm just a bit stuck and would appreciate any comments.
Many thanks in advance,

Your server is handling just one connection. You should use an array of connections (#socket).
You have two infinite loops nested. Since the inner one is never going to finish, you are going to attend only the first connection.
This seems a typical chat server, so i recommend you to search Google for "perl chat server". Here you have some source code that can be of help:
http://sourceforge.net/projects/perlchat/

Related

Established TCP connection but socket doesn't send/recv data

I'm writing a simple TCP client and server Perl script.
As of now I verify the 3 way TCP handshake using wireshark, and the connection is established.
But when i try to send or recv data nothing happens.
Questions:
1) the major difference between the client and the server is only that the server has an added LISTEN parameter which enables it to listen for incoming connections ?
2)Are there any steps missing between recv and displaying the data?
3)Shouldn't atleast the hardcoded string "$response" be sent when the program executes the while loop the first time?
4)How do shutdown($sock,1) and sleep(1) differ in this implementation? Is it okay to let the socket sleep or should I use shutdown($sock,1) to signal to the client/server that data has been sent ?
on inspecting the status of the connection in wireshark, i've noticed that only the handshake takes place. there is no data exchanged at all. So im pretty sure the problem lies somewhere on writing to the socket and reading data from the socket (using the keyboard or hardcoded strings).
Any help would be really appreciated.
The client is as follows:
#!/usr/bin/perl
use IO::Socket;
use Getopt::Long;
#$IP_addr = $ARGV[0];
#$tgt_port = $ARG[1];
#netcat client
$port = 9040;
$sock = IO::Socket::INET->new( PeerAddr => 'localhost',
PeerPort => $port,
LocalPort => 9000,
Proto => 'tcp')
or die "\nunable to bind on localhost : $port...";
while ($sock){
#Get the clients IP and port number
$client_IP = $sock -> peerhost();
#$client_IP = 'localhost';
$client_port = $sock -> peerport();
print "\n Connected to $client_IP $client_port \n";
#Reading from socket
$data;
$sock ->recv($data, 1024);
print $data;
#writing to socket
$sock->autoflush(1);
$response = "response: OK recvd\n" ;
$sock->send($response);
shutdown($sock,1);
}
$sock -> close();
The server is as follows:
#!/usr/bin/perl
use IO::Socket;
use Getopt::Long;
#$IP_addr = $ARGV[0];
#$tgt_port = $ARG[1];
#netcat server
$port = 9040;
$sock = IO::Socket::INET->new( Listen => 1,
LocalAddr => 'localhost',
LocalPort => $port,
Proto => 'tcp')
or die "\nunable to bind on localhost : $port...";
while ($sock){
print "\nListening on port $port ...\n";
$sock = $sock -> accept();
#Get the clients IP and port number
$client_IP = $sock->peerhost();
$client_port = $sock->peerport();
print "\n Connected from $client_IP $client_port \n";
#Reading from socket
$data ->recv($sock, 1024);
print $data;
#writing to socket
$sock->autoflush(1);
$response = "oohlalala" ;
$sock -> send($response);
shutdown($sock, 1);
}
$sock -> close();
From IO::Socket:
As of VERSION 1.18 all IO::Socket objects have autoflush turned on by
default. This was not the case with earlier releases.
Perl version 2.0 was released in 1988. You are most likely using perl version 5.x.
1) the major difference between the client and the server is only that
the server has an added LISTEN parameter which enables it to listen
for incoming connections ?
According to the docs:
If Listen is defined then a listen socket is created...
A listen socket can call accept(). If a regular socket calls accept(), accept() returns undef.
accept()
In a scalar context the new socket is returned, or undef upon failure.
In a list context a two-element array is returned containing the new
socket and the peer address; the list will be empty upon failure.
https://perldoc.perl.org/IO/Socket.html
Here is a nice, short, basic description of sockets.
Your server code probably hides some of what's going on. It would be more illustrative if it was written like this:
$server_socket = IO::Socket::INET(.....);
...
...
my $client_socket = $server_socket->accept();
...
...
There are two different sockets. accept() returns a new socket for the server and the client to communicate with, so the original server socket can keep listening for client connections.
2) Are there any steps missing between recv and displaying the data?
Depending on what you're doing, you might want to get rid of the characters that mark the end of the data, which the code would have used to signal the other side that it should stop trying to read more data from the socket.
Receiving the data is the tricky part. An agreed upon protocol must be used by both the client and the server to avoid deadlock, which is when both the client and the server are waiting for the other side to send data. In the example below, I employ a "line oriented" protocol where one side stops reading from the socket when it reads a newline. In networking, by convention a newline is considered to be "\r\n", which represents the ascii characters carriage return and line feed, but to avoid any type of automatic "\n" translations on various OS's, the socket library uses the actual ascii codes: 13 and 10, which in hex notation is: "\x0D\x0A".
server.pl:
use strict;
use warnings;
use 5.020;
use autodie;
use Data::Dumper;
use IO::Socket::INET;
use Socket qw( :crlf ); # "\x0D\x0A" constants CRLF and $CRLF
my $host = 'localhost';
my $port = 15_678;
my $server_socket = IO::Socket::INET->new(
Listen => 5,
LocalPort => $port,
LocalAddr => $host,
Proto => 'tcp',
ReuseAddr => 1,
ReusePort => 1
);
say "Server listening on port: $port\n";
while (my $client_socket = $server_socket->accept() ) {
my $client_ip = $client_socket->peerhost();
my $client_port = $client_socket->peerport();
say "Connection from $client_ip:$client_port";
{
local $/ = CRLF; # $/ is the input record separator, which is "\n"
#by default. Both <$INFILE> and getline() read up to
#and including the input record separator.
while(my $line = $client_socket->getline) { #Blocks until CRLF is read
#from the socket or the other
#side closes the socket.
chomp $line; #chomp() removes input record separator from end of line.
say "Server received: $line";
my $response = reverse $line;
$client_socket->send("$response$CRLF");
say "Server sent: $response";
}
} #Here $/ is restored to whatever it was before this parenthesized block.
#That is what declaring a variable as local does.
say "-" x 30;
#Execution arrives here after the client closes the socket:
$client_socket->shutdown(2); #Send signals to other side of socket.
#Not necessary in this example because other threads
#aren't also reading from the socket.
$client_socket->close(); #Close the filehandle associated with the socket.
}
Note that just like when reading a file, getline will return everything it has read so far when it receives an eof signal, and for the next iteration of the while loop getline will return undef causing the while loop to terminate.
client.pl:
use strict;
use warnings;
use 5.020;
use autodie;
use Data::Dumper;
use IO::Socket::INET;
use Socket qw( :crlf ); #\x0D\x0A constants CRLF and $CRLF
my $port = 15_678;
my #lines = (
"hello world",
"goodbye mars",
);
my $sock = IO::Socket::INET->new("localhost:$port");
for my $line(#lines){
my $server_ip = $sock->peerhost();
my $server_port = $sock->peerport();
say "Connected to $server_ip:$server_port";
$sock->send("$line$CRLF");
say "Client sent: $line";
my $response;
{
local $/ = CRLF;
$response = $sock->getline();
chomp $response;
}
say "Client received: $response";
say '-' x 30;
}
#Tell the server that no more data is coming from this client:
$sock->shutdown(2); #Send signals to other side of socket.
$sock->close(); #Close the filehandle associated with the socket.
After running the client program twice...
Server output:
Server listening on port: 15678
Connection from 127.0.0.1:56085
Server received: hello world
Server sent: dlrow olleh
Server received: goodbye mars
Server sent: sram eybdoog
------------------------------
Connection from 127.0.0.1:56096
Server received: hello world
Server sent: dlrow olleh
Server received: goodbye mars
Server sent: sram eybdoog
------------------------------
Client output:
$ perl client.pl
Connected to 127.0.0.1:15678
Client sent: hello world
Client received: dlrow olleh
------------------------------
Connected to 127.0.0.1:15678
Client sent: goodbye mars
Client received: sram eybdoog
------------------------------
$ perl client.pl
Connected to 127.0.0.1:15678
Client sent: hello world
Client received: dlrow olleh
------------------------------
Connected to 127.0.0.1:15678
Client sent: goodbye mars
Client received: sram eybdoog
------------------------------
$
3) Shouldn't atleast the hardcoded string "$response" be sent when the
program executes the while loop the first time?
Yes, all statements in a while loop will have executed after the first loop has finished executing--but when a statement higher up in the loop is blocking, then the send will never execute.
4) How do shutdown($sock,1) and sleep(1) differ in this implementation? Is it okay to let the socket sleep or should I use
shutdown($sock,1) to signal to the client/server that data has been
sent ?
I'm not sure how shutdown() and sleep() are related in any way. sleep() stops your code from executing for the specified time, while shutdown() sends something to the other side of a socket.
"Closing the socket", i.e. calling shutdown(), to mark the end of the data is another protocol that you can adopt. It makes things pretty easy: one side just continues to read from the socket in some sort of read statement, and when the other side closes the socket, the read will return. Here's an example:
server.pl:
use strict;
use warnings;
use 5.020;
use autodie;
use Data::Dumper;
use IO::Socket::INET;
my $host = 'localhost';
my $port = 15_678;
my $server_socket = IO::Socket::INET->new(
Listen => 5,
LocalPort => $port,
LocalAddr => $host,
Proto => 'tcp',
ReuseAddr => 1,
ReusePort => 1
);
say "Server listening on port: $port\n";
while (my $client_socket = $server_socket->accept() ) {
my $client_ip = $client_socket->peerhost();
my $client_port = $client_socket->peerport();
say "Connection from $client_ip:$client_port";
my $data;
{
local $/ = undef; #This input record separtor will never be found...
$data = <$client_socket>; #...so this reads everything--including newlines--until it gets an eof signal.
}
say "Server received: $data";
my $response = reverse $data;
$client_socket->send($response);
$client_socket->shutdown(2); #Doesn't close filehandle -- merely sends signals.
$client_socket->close(); ##Close the filehandle associated with the socket.
say "Server sent: $response";
say "-" x 30;
}
client.pl:
use strict;
use warnings;
use 5.020;
use autodie;
use Data::Dumper;
use IO::Socket::INET;
my $port = 15_678;
my #data = (
"hello \n world", #Now newlines are in the data
"goodbye \n mars",
);
for my $data (#data){
my $sock = IO::Socket::INET->new("localhost:$port");
my $server_ip = $sock->peerhost();
my $server_port = $sock->peerport();
say "Connected to $server_ip:$server_port";
$sock->send($data);
say "Client sent: $data";
$sock->shutdown(1);
my $response;
{
local $/ = undef; #This input record separtor will never be found...
$response = <$sock>; ##...so this reads everything--including newlines--until it gets an eof signal.
}
$sock->shutdown(0);
$sock->close();
say "Client received: $response";
say '-' x 30;
}
Server output:
Server listening on port: 15678
Connection from 127.0.0.1:53139
Server received: hello
world
Server sent: dlrow
olleh
------------------------------
Connection from 127.0.0.1:53140
Server received: goodbye
mars
Server sent: sram
eybdoog
------------------------------
Client output:
Connected to 127.0.0.1:15678
Client sent: hello
world
Client received: dlrow
olleh
------------------------------
Connected to 127.0.0.1:15678
Client sent: goodbye
mars
Client received: sram
eybdoog
------------------------------
Code for the server (tested with telnet localhost 9040):
use strict;
use warnings;
use IO::Socket::INET;
my $port = 9040;
my $listen = IO::Socket::INET->new(Listen => 1,
LocalPort => $port,
Proto => 'tcp',
ReuseAddr => 1,
ReusePort => 1);
while ($listen) {
print "\nListening on port $port ...\n";
my $sock = $listen->accept();
my $client_IP = $sock->peerhost();
my $client_port = $sock->peerport();
print "\n Connected from $client_IP $client_port \n";
my $data;
$sock->recv($data, 1024);
print $data;
#writing to socket
$sock->autoflush(1);
my $response = "oohlalala\n" ;
$sock->send($response);
shutdown($sock, 1);
}
Client code (tested against above server):
use strict;
use warnings;
use IO::Socket::INET;
my $port = 9040;
my $sock = IO::Socket::INET->new(PeerAddr => 'localhost',
PeerPort => $port,
Proto => 'tcp');
if ($sock) {
my $server_IP = $sock->peerhost();
my $server_port = $sock->peerport();
print "\n Connected to $server_IP $server_port \n";
# initiate protocol
$sock->autoflush(1);
print $sock "OK\n";
my $data;
$sock->recv($data, 1024);
print $data;
shutdown($sock, 1);
}
Output from server:
Listening on port 9040 ...
Connected from 127.0.0.1 36106
OK
Listening on port 9040 ...
Output from client:
Connected to 127.0.0.1 9040
oohlalala

Perl, websocket in infinite loop

I have a perl script that worked as a “middle men” between a local program and an external interactive website.
The problem is that the external website migrated from plain tcp connection to a websocket connection.
When the server was using tcp, after initial connection, the client (the script) and the server (external website) will go thru a handshake, then the script will send the username and password and server will finally respond with some encryption keys, afterwards the script will go into an infinite loop and waited for data from both connections and then process that data and "print" back to the connections as needed.
I had been able to establish the websocket connection with the server using the Mojo::UserAgent as well as with protocol::websocket, go thru the handshake and the other information exchange (username, password, etc), but I have not been able (or better said: I do not know how) to "throw" the websocket connection into the infinite loop via IO::Select ( The reason I want to use IO::Select is because doing so will require minimal changes to the script, but other suggestions are definitely welcome).
The relevant parts of the script are as follows:
# Creating connection for local program
$lsn=new IO::Socket::INET(
Proto => 'tcp',
LocalPort => 6000,
Listen => 1,
);
unless(defined $lsn){
print"$0: $!\n";
exit 1;
}
print"Waiting for local program connection on port 6000\n";
$server=$lsn->accept;
$lsn->close;
unless(defined $server){
print "$0: Unable to accept incoming connection: $!\n";
exit 1;
}
# At this point, the script is waiting for a connection from
# the local program on port 6000
printf"Connection accepted from %s\n",$server->peerhost;
select $server;
binmode $server;
$stdin=$server;
(select)->autoflush(1);
# Creating connection for external website
$net=new IO::Socket::INET(
Proto => 'tcp',
PeerAddr => $yog,
PeerPort => $yserverport,
);
unless(defined($net)){
print "Can't connect!\n";
exit 1;
}
$net->autoflush(1);
####################################
# Here the script and server will #
# exchange information few times #
####################################
my $sel=new IO::Select($stdin,$net);
$net->autoflush(0);
while (1){
foreach my $i($sel->can_read(0.05)){
if($i==$net){
&dosomething;
$net->flush;
}
else{
&dosomething2;
$net->flush;
}
}
}
The infinite loop examples that I have found, are not suitable in this case because I need to use an infinite loop that can check for incoming data on both connections.
WebSockets require a lot than asimple IO Socket. They require handshakes and data framing. I would review the W3C WebSocket API and then look into using a perl module (Net::WebSocket::Server) to do the heavy lifting. Also, webSockets will only work with the chrome browser using SSL so if are interested in cross compatibility, use Net::WebSocket::Server with IO::Socket::SSL instead and here is a working sample of SSL:
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::SSL;
use Net::WebSocket::Server;
my $ssl_server = IO::Socket::SSL->new(
Listen => 5,
LocalPort => 4000,
Proto => 'tcp',
SSL_cert_file => '/var/ssl/cert.crt',
SSL_key_file => '/var/ssl/cert.key',
) or die "failed to listen: $!";
my $port = 6000;
my $origin = 'https://YOURDOMAIN.com';
Net::WebSocket::Server->new(
listen => $ssl_server,
on_connect => sub {
our ($serv, $conn) = #_;
$conn->on(
handshake => sub {
my ($conn, $handshake) = #_;
$conn->disconnect() unless $handshake->req->origin eq $origin;
},
utf8 => sub {
my ($conn, $msg) = #_;
my $MyIP = $conn->ip();
my $MyPORT = $conn->port();
$_->send_utf8($msg) for( $serv->connections() );
},
);
},
)->start;
If you are not concerned with Chrome or SSL here is a working non-SSL example, (It needs use strict and use warnings):
#!/usr/bin/perl
use Net::WebSocket::Server;
my $port = 6000;
Net::WebSocket::Server->new(
listen => $port,
on_connect => sub {
my ($serv, $conn) = #_;
$conn->on(
utf8 => sub {
my ($conn, $msg) = #_;
$_->send_utf8($msg) for( $serv->connections() );
},
);
},
)->start;
Also, if you decide to use the SSL version, make sure to update your client side from ws:// to wss://

Check if UDP port is opened in Perl

I need to check if remote UDP port is opened. My part of code is:
sub scanUDP {
my $address = shift;
my $port = shift;
my $udpSocket = new IO::Socket::INET (
PeerAddr => $address,
PeerPort => $port,
Proto => 'udp',
) or return 0;
$udpSocket -> send ('hello', 0);
#........SOME CODE.............
return 1;
}
..SOME CODE.. should check if I received ICMP packets "Host unreached" or "Port unreached" to check if port is opened. But how can I do it?
Generally you can't. UDP does not have a connected state, so it is in no way required to send you any reply to the packet you sent. And that's even when ignoring package loss. You may get a positive reply if you sent a valid request in whatever protocol you're accessing and the remote port is open, but the absence of such a reply can not be used to make any conclusions.
If you really get an ICMP unreachable back you will receive the error with a later send call (unless you peer is localhost, than you might get it with the first one already). But there is no guarantee that you will get an ICMP unreachable back at all, because either ICMP or the UDP itself might be filtered by a firewall.
It looks like it will not report the problem on windows this way, but you can use recv there instead of send (works on UNIX too). The error code is probably something specific to windows, ECONNREFUSED works only on UNIX:
use strict;
use warnings;
use IO::Socket::INET;
my $cl = IO::Socket::INET->new(
PeerAddr => '192.168.122.42:12345', # definitly rejecting
Proto => 'udp',
);
$cl->send('foo') or die "send failed: $!"; # first send will succeed
# wait some time to receive ICMP unreachable
sleep(1);
$cl->blocking(0);
if ( ! $cl->recv( my $buf,0)) {
# will get ECONNREFUSED on UNIX, on Win the code is different
warn "error $!" if ! $!{EAGAIN};
}
This is the code that works for me:
sub scanUDP {
my $address = shift;
my $port = shift;
my $socket = new IO::Socket::INET (
PeerAddr => $address,
PeerPort => $port,
Proto => 'udp',
) or return 0;
$socket -> send('Hello',0);
my $select = new IO::Select();
$select -> add($socket);
my #socket = $select -> can_read(1);
if (#socket == 1) {
$socket -> recv(my $temp, 1, 0) or return 0;
return 1;
}
return 1;
}

Error in perl chat server

I'm trying to create a chat server using sockets in Perl. However, when I run the Server program I get the error:
"ERROR:(9)(Bad file descriptor)(6)(+The handle is invalid) at Server.pl line 21."
and when I run the client program I get the error:
"Cannot create the socket: No connection could be made because the target machine
actively refused it."
Here is the Server program:
#!usr/bin/perl
#server.pl
use IO::Socket;
$| = 1;
print "Server Program\n";
my $lp = 12000;
my $server_socket, $new_client, $addr, $port;
$server_socket = new IO::Socket::INET (
LocalHost => '127.0.0.1',
LocalPort => $lp,
Proto => 'tcp',
Reuse => 1) or die "Cannot create the socket: $!\n";
print "Server started at port $lp \n";
while (1) {
$new_client = $server_socket->accept() or die sprintf "ERROR:(%d)(%s)(%d)(+%s)", $!,$!,$^E,$^E;
$addr = $new_client->peerhost();
$port = $new_client->peerport();
print "Connected to client at $addr at port $port ";
while(<$new_client>) {
print "Following is the text entered by client: \n";
print "$_";
}
print "Client now disconnecting..\n";
close $new_client;
}
$server_socker->close();
And here is the client:
#!usr/bin/perl
#client.pl
use IO::Socket;
$| = 1;
print "Client Program\n";
my $lp = 12000;
my $client_socket = new IO::Socket::INET (
PeerHost => '127.0.0.1',
PeerPort => $lp,
Proto => 'tcp',
Reuse => 1) or die "Cannot create the socket: $!\n";
print "Server connected at port $lp \n";
print "Enter the text to sent to the server: \n";
$user_input = <>;
chomp $user_input;
print $plient_socket;
$client_socket->send($user_input);
$client_socket->close();
I am new to this and I'm not getting where I'm going wrong. Could anybody help?
You trying to accept a connection from a socket that's not listening. Add
Listen => SOMAXCONN,
And now for off-topic comments about your code:
Always use use strict; use warnings;. It will highlight some other problems with your code.
It doesn't make any sense to relative paths on the shebang line. You're missing a /.
On the style front, it's considered bad form to declare variables ahead of where they are used. The whole point of declaring variables is to limit their scope, so declaring them at the top of the program defies the purpose.
LocalHost => '127.0.0.1' (better written as LocalHost => INADDR_LOOPBACK) makes it so you can only receive connections from 127.0.0.1. That can be useful, but I don't know if you did that intentionally. The default, INADDR_ANY, allows connections from any interface.

problem with IO::Socket TCP connection

I am trying to write a simple IO::Socket connection in perl. However, I am running into some problems. Here is the code on the server side:
my $listener =
IO::Socket::INET->new( LocalPort => 8000, Listen => 1, Reuse => 1 );
die "Can't create socket for listening: $!" unless $listener;
print "Listening for connections on port 8000\n";
while(1) {
while ($client = $listener->accept()) {
while ( <$client>) {
my #arguments = split(/ /, $_ );
my $result = "something" ;# here we do something in my code
warn $result;
print $client $result;
close $client;
}
}
}
And the client code:
use IO::Socket;
my $sock = new IO::Socket::INET (
PeerAddr => 'xx.xxx.xxx.xxx',
PeerPort => '8000',
Proto => 'tcp',
);
die "Could not create socket: $!\n" unless $sock;
$sock->autoflush(1);
print $sock "somethin something";
print "sent\n";
while ( <$sock> ) { print }
close $sock;
My problem now is that the data seems to be only sent from the client to teh sever when I close the client Perl program. I get the "sent" message on the client side, but the "something" message on the server side does not appear until after I have manually closed the client side.
Also, I want to get the server response. Thus far, since I have to close the script manually, the response does not et to the client side.
Can anyone help?
while ( <$sock> ) -- waits for a line. That is for a string, ended by "\n" character.
You must add "\n" to strings, or use 'read' function instead.