How to Secure a port opened in the host? - perl

Our goal is to monitor the server up/down from a remote(central) server. For this we are opening a port in the target host using the below (Client_port.pl) script. On the server we have other script to monitor this port, to make sure the server is up and port is up. Both the server wouldn't be on same network, so we need to open the client port to the world. How would we secure the client port from security hole and other possible harmful issues?
Client_port.pl
use IO::Socket::INET;
$server = IO::Socket::INET->new(LocalPort => $server_port,
Type => SOCK_STREAM,
Reuse => 1,
Listen => 10 ) # or SOMAXCONN
or die "Couldn't be a tcp server on port $server_port: $!\n";
while ($client = $server->accept()) {
# $client is the new connection
}
close($server);
Server_port_listener.pl
use strict;
use Socket;
# set time until connection attempt times out
my $timeout = 3;
if ($#ARGV != 1) {
print "usage: is_tcp_port_listening hostname portnumber\n";
exit 2;
}
my $hostname = $ARGV[0];
my $portnumber = $ARGV[1];
my $host = shift || $hostname;
my $port = shift || $portnumber;
my $proto = getprotobyname('tcp');
my $iaddr = inet_aton($host);
my $paddr = sockaddr_in($port, $iaddr);
socket(SOCKET, PF_INET, SOCK_STREAM, $proto) || die "socket: $!";
eval {
local $SIG{ALRM} = sub { die "timeout" };
alarm($timeout);
connect(SOCKET, $paddr) || error();
alarm(0);
};
if ($#) {
close SOCKET || die "close: $!";
print "$hostname is NOT listening on tcp port $portnumber.\n";
exit 1;
}
else {
close SOCKET || die "close: $!";
print "$hostname is listening on tcp port $portnumber.\n";
exit 0;
}

Related

Net::OpenSSH how to make perl script not exit and move to next IP if authentication fails

I am a beginner to Perl. My objective is to run a loop on a list of router IPs and attempt to ssh login into them, execute some commands, and store the output.
Upon unsuccessful authentication of one router IP, the entire script stops, and it does not move to the next IP. I wish to store why authentication failed of the router IP in question, and then move onto the next IP to execute.
The error I get before the script exits is:
Unable to connect: unable to establish master SSH connection: bad
password or master process exited unexpectedly
#!/usr/bin/perl -s
use Net::OpenSSH;
my $password = "xxxxxxx";
my $s;
$filename1 = "ip_FINAL_sample";
open my $f1, '<', "$filename1.txt";
chomp(my #file1 = <$f1>);
close $f1;
for $loopvariable(#file1)
{
my #mikparameters = split /\|/, $loopvariable;
$mikip = $mikip . $mikparameters[0] . "\n";
}
my #routers = split "\n", $mikip;
my $cmd1 = 'system identity print';
my $cmd2 = 'system routerboard print';
foreach $s (#routers)
{
my $ssh = Net::OpenSSH->new("yyyyy+500w\#$s", password=>$password, timeout=>30);
$ssh->error and die "Unable to connect: " . $ssh->error;
print "connected to $s\n";
my $fh1 = $ssh->pipe_out($cmd1) or die "Unable to run command\n";
my $fh1_1 = $ssh->capture($cmd1) or die "Unable to run command\n";
my $fh2 = $ssh->pipe_out($cmd2) or die "Unable to run command\n";
my $fh2_2 = $ssh->capture($cmd2) or die "Unable to run command\n";
while (<$fh1>)
{
print "$_";
}
close $fh1;
print "\n";
open my $file1, '>>', "output.txt" or die "Can't open output.txt: $!\n";
print $file1 "$fh1_1";
close $file1;
while (<$fh2>)
{
print "$_";
}
close $fh2;
print "\n";
open my $file2, '>>', "output.txt" or die "Can't open output.txt: $!\n";
print $file2 "$fh2_2";
close $file2;
undef $ssh;
}

Perlscript with only one instance running, the next call add to queue of the first

I trie to make a Perlscript where only one instance is running, and the next call of the script sends the payload to the queue of the first one. If the queue is done the script should terminate.
I tried this with sockets - they should be blocking... I use Win7
If I call this script with test1 and test2 in two different command windows booth tell me they open the port and the queue echo back but don't terminate.
use 5.14.2;
use strict;
use warnings;
#Filename: singleInstance.pl
use Socket;
use threads;
use Thread::Queue;
sub sendToPort($);
my $q = Thread::Queue->new(); # A new empty queue
# Worker thread
my $thr = threads->create(
sub {
# Thread will loop until no more work
while (defined(my $item = $q->dequeue())) {
say $item;
sleep 10;
}
die "all done";
}
);
my $string = shift;
my $proto = getprotobyname('tcp');
my $port = 7890;
my $server = "localhost";
socket(SOCKET, PF_INET, SOCK_STREAM, $proto)
or die "Can't open socket $!\n";
setsockopt(SOCKET, SOL_SOCKET, SO_REUSEADDR, 1)
or die "Can't set socket option to SO_REUSEADDR $!\n";
bind( SOCKET, pack_sockaddr_in($port, inet_aton($server)))
or die sendToPort($string);
listen(SOCKET, 5) or die "listen: $!";
print "SERVER started on port $port\n";
$q->enqueue($string);
# accepting a connection
my $client_addr;
while ($client_addr = accept(NEW_SOCKET, SOCKET)) {
# send them a message, close connection
my $string = <NEW_SOCKET>;
$q->enqueue($string);
close NEW_SOCKET;
}
sub sendToPort($){
# create the socket, connect to the port
socket(SOCKET,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2])
or die "Can't create a socket $!\n";
connect( SOCKET, pack_sockaddr_in($port, inet_aton($server)))
or die "Can't connect to port $port! \n";
print SOCKET $string;
close SOCKET or die "close: $!";
die "send to open script";
}
It seams that with Windows Port blocking don't work and also flock on the script if the script should be used when locked. I used a lock on a file instead. If the queue is done it exit the script. It's not the best solution, but it works for me so I didn't researched it more.
use 5.14.2;
use strict;
use warnings;
use Socket;
use threads;
use Thread::Queue;
use File::Flock::Tiny;
sub sendToPort($);
my $string = shift;
my $proto = getprotobyname('tcp');
my $port = 7890;
my $server = "localhost";
my $pid = File::Flock::Tiny->write_pid('cl_sv.pid') or do
{
say "in lock. send to daemon: $string";
sendToPort($string);
exit(0);
};
my $q = Thread::Queue->new(); # A new empty queue
# Worker thread
my $thr = threads->create(
sub {
# Thread will loop until no more work
while (defined(my $item = $q->dequeue())) {
say $item;
sleep 5;
}
exit;
}
);
my $socket;
socket($socket, PF_INET, SOCK_STREAM, $proto)
or die "Can't open socket $!\n";
setsockopt($socket, SOL_SOCKET, SO_REUSEADDR, 1)
or die "Can't set socket option to SO_REUSEADDR $!\n";
bind( $socket, pack_sockaddr_in($port, inet_aton($server)))
or die;
listen($socket, 5) or die "listen: $!";
print "SERVER started on port $port\n";
$q->enqueue($string, undef);
# accepting a connection
my $client_addr;
my $new_socket;
while ( ($client_addr = accept($new_socket, $socket))) {
# send them a message, close connection
my $string = <$new_socket>;
my $remove_undef= $q->extract(-1);
$q->enqueue($string, undef);
close $new_socket;
}
sub sendToPort($){
# create the socket, connect to the port
print "sendToPort";
socket($socket,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2])
or die "Can't create a socket $!\n";
connect( $socket, pack_sockaddr_in($port, inet_aton($server)))
or die "Can't connect to port $port! \n";
print $socket $string;
close $socket or die "close: $!";
#die "send to open script";
}

Turn off echo IO::Socket::INET

I am trying to create a remote-login script with perl. I am currently getting input data using
$var = <$client>;
chomp $var;
However, I am trying to have the client input a password and I want to hide the password in the linux fashion with the client by not echoing what is typed. Is there any way I can do this?
EDIT:
$serv = IO::Socket::INET->new (
Proto => 'tcp',
LocalPort => $port,
Listen => 10,
Reuse => 1)
|| die "Can't create server: $!";
while ($client = $serv->accept()) {
eval {
$client->autoflush(1); # Always remember to flush!
$who = $client->peerhost;
print STDERR "Connection from $who\n";
print $client hostname . " login: ";
$usr = <$client>;
chomp $usr;
$usr =~ s/\W//g;
print STDERR "User $usr\n";
die unless (length $usr < 20 && length $usr > 1);
print $client "Encrypted Password: ";
$pass = <$client>;
chomp $pass;
die unless (length $pass < 20 && length $pass > 1);
print STDERR "$who: Pass $pass\n";
};
close $client;
}
This is local console echo, nothing to do with your socket.
There are many ways to turn off console echo using Perl, but my favourite is IO::Termios (perhaps I'm biased because I wrote it ;) )
use IO::Termios;
my $stdin = IO::Termios->new(\*STDIN);
$stdin->setflag_echo(0);

Multiple string parse to loop

I currently have some code which returns a sites header content back:
#!/usr/bin/perl
use strict;
require IO::Socket;
my #header;
my $host = shift;
my $socket = new IO::Socket::INET(
PeerAddr => $host,
PeerPort => 80,
Proto => 'tcp') || die "Could not Connect $!\n";
print "Connected.\n";
print "Getting Header\n";
print $socket "GET / HTTP/1.0\n\n";
my $i = 0;
while (<$socket>) {
#header[$i] = $_;
$i++;
}
$i = 0;
print "--------------------------------------\n";
while ($i <= 8) {
print "#header[$i++]";
}
print "-------------------------------------\n";
print "Finished $host\n";
What I would like to do, is to be able to read from a file open (FILE, '<', shift); and then every IP in the file, to pass into a the header retrieve loop, which saves me from manually doing one by one.
What I mean by this is to have a file containing (example ips): 1.1.1.1 2.2.2.2 on each line and then parsing all of them through the get header function.
Replace
my #header;
my $host = shift;
...
with
while (<>) {
chomp( my $host = $_ );
my #header;
...
}
You would just open your file, read the contents into a list, then iterate over the list:
open my $fh, '<', $file or die "$!";
my #ips = <$fh>;
close $fh;
foreach my $ip ( #ips ) {
chomp $ip;
...
}

FTP application written in Perl doesn't connect

Why doesn't my program work? It refuses to connect to the host, I've tried two different servers and verified which port is used.
Note that I'm not very experienced when it comes to Perl.
use strict;
use Net::FTP;
use warnings;
my $num_args = $#ARGV+1;
my $filename;
my $port;
my $host;
my $ftp;
if($num_args < 2)
{
print "Usage: ftp.pl host [port] file\n";
exit();
}
elsif($num_args == 3)
{
$port = $ARGV[1];
$host = $ARGV[0];
$filename = $ARGV[2];
print "Connecting to $host on port $port.\n";
$ftp = Net::FTP->new($host, Port => $port, Timeout => 30, Debug => 1)
or die "Can't open $host on port $port.\n";
}
else
{
$host = $ARGV[0];
$filename = $ARGV[1];
print "Connecting to $host with the default port.\n";
$ftp = Net::FTP->new($host, Timeout => 30, Debug => 1)
or die "Can't open $host on port $port.\n";
}
print "Usename: ";
my $username = <>;
print "\nPassword: ";
my $password = <>;
$ftp->login($username, $password);
$ftp->put($filename) or die "Can't upload $filename.\n";
print "Done!\n";
$ftp->quit;
Thanks in advance.
Now that you already have your answer <> -> <STDIN>, I think I see the problem. When #ARGV contains anything, <> is the 'magic open'. Perl interprets the next item in #ARGV as a filename, opens it and reads it line by line. Therefore, I think you can probably do something like:
use strict;
use Net::FTP;
use warnings;
use Scalar::Util 'looks_like_number';
if(#ARGV < 2)
{
print "Usage: ftp.pl host [port] file [credentials file]\n";
exit();
}
my $host = shift; # or equiv shift #ARGV;
my $port = (looks_like_number $ARGV[0]) ? shift : 0;
my $filename = shift;
my #ftp_args = (
$host,
Timeout => 30,
Debug => 1
);
if ($port)
}
print "Connecting to $host on port $port.\n";
push #ftp_args, (Port => $port);
}
else
{
print "Connecting to $host with the default port.\n";
}
my $ftp = Net::FTP->new(#ftp_args)
or die "Can't open $host on port $port.\n";
#now if #ARGV is empty reads STDIN, if not opens file named in current $ARGV[0]
print "Usename: ";
chomp(my $username = <>); #reads line 1 of file
print "\nPassword: ";
chomp(my $password = <>); #reads line 2 of file
$ftp->login($username, $password);
$ftp->put($filename) or die "Can't upload $filename.\n";
print "Done!\n";
$ftp->quit;
Then if you had some connection creditials in a file (say named cred) like
myname
mypass
then
$ ftp.pl host 8020 file cred
would open host:8020 for file using credentials in cred.
I'm not sure you want to do that, its just that THAT is how <> works.