Perl SSH connection to execute telnet - perl

I tried the following to access a router via a central admin server as "ssh hop" server
#!/usr/bin/perl -X
use strict;
use Net::OpenSSH;
use Net::Telnet;
my $lhost = "linuxserver";
my $luser = "linuxuser";
my $lpass = "linuxpassword";
my $chost = "routername";
my $cpass = "Routerpassword";
my $prompt = '/(?:Password: |[>])/m';
my #commands = ("show users\r");
my $ssh = Net::OpenSSH->new($lhost,
'user' => $luser,
'password' => $lpass,
'master_opts' => [ '-t' ],
#'async' => 1 # if enabled then password cannot be set here
);
my ($pty, $err, $pid) = $ssh->open2pty("telnet $chost");
my $t = new Net::Telnet(
-telnetmode => 0,
-fhopen => $pty,
-prompt => $prompt,
-cmd_remove_mode => 1,
-output_record_separator => "\r",
#-dump_log => "debug.log",
);
my $end = 0;
while (!$end) {
my ($pre, $post) = $t->waitfor($prompt);
if ($post =~ /Password: /m) {
# send password
$t->print("$cpass");
}
elsif ($post =~ /[>#]/ && #commands) {
my $cmd = shift(#commands);
if ($cmd !~ /[\r\n]/) {
$t->print($cmd);
}
else {
print $t->cmd($cmd);
}
}
else {
$end = 1;
$t->cmd("exit");
}
}
#close $pty;
$t->close();
Unfortunately I always get the following error:
read error: Input/output error at test.pl line 71
Can somebody help me please or is there a better solution only to test if a telnet connection via the "hop" server is possible or not?
The connection looks like:
workstation --ssh-> server --telnet-> router
Thanks in advance.

I think best option is to make an SSH-tunnel to your admin server and use it for telnetting to the router.

Getting Net::Telnet to work over Net::OpenSSH sometimes is not as easy as it should be and it requires some experimentation to get to the right combination of flags and calls that make it work.
For instance, instead of telneting to the target host, use netcat to open a raw connection (or Net::OpenSSH support for TCP forwarding if tunnels are allowed on the proxy).
Expect + Net::OpenSSH may be a better option.

Related

Perl, Sendgrid and Net::SMTP and MIME::Entity

In my Perl code, I was using Net::SMTP and MIME:Entity to send email through my Sendgrid account (from their v2 api, where I could use my account login as the api)...
it was working flawlessly.
But we moved servers to a newer version.
Still Unix (Linux), but has newer hardware, including a newer version of Plesk.
The IP addresses are all the same, we moved them to the new hardware. We did change the IP address that is the primary one, but we made sure we added it to sendgrid whitelabel...
So I'm clueless why it would stop working.
I am not getting any errors in the code, the api is connecting. But I don't ever see any emails, no matter what I do.
Since no errors, not sure why it does not work.
Here is my code, do you see the flaw that would make it fail?
sub Send_Multi_Part_Email_MimeLite {
my ($__to,$__cc,$__bcc,$__from,$__subject,$__html_message,$__text_message,$__importance,$__xpriority,$__x_ms_priority) = #_;
if($__x_ms_priority && ($__x_ms_priority =~ /\|/)) {
($__x_ms_priority,$_attachFile,$_attachFilePath) = split /\|/, $__x_ms_priority, 3;
}
if($__xpriority && ($__xpriority =~ /\|/)) {
($__xpriority,$_unSubKey,$_mbrUn) = split /\|/, $__xpriority, 3;
}
if($__importance && ($__importance =~ /\|/)) {
($__importance,$_emailType) = split /\|/, $__importance, 2;
}
my $_useNewSystem = 1; # Declare new system... set to 1 to use it and not use MimeLite any longer...
if($_useNewSystem) {
use MIME::Entity;
use Net::SMTP;
my $_sendIp = $ENV{REMOTE_ADDR} || "127.0.0.1";
if($__to && ($__to =~ /\;/)) {
$__to =~ s/\;/\,/g;
}
if($__cc && ($__cc=~ /\;/)) {
$__cc =~ s/\;/\,/g;
}
if(!$__bcc) {
$__bcc = 'testmailacct#gmail.com'; # not real, but when in production is a real email, so we can get emails to confirm they are being delivered... only when debugging... Commented out if not in test mode...
}
if($__bcc && ($__bcc =~ /\;/)) {
$_bcc =~ s/\;/\,/g;
}
if(!$__html_message) {
$__html_message = $__text_message;
$__html_message =~ s/\n/br()."\n"/eg;
$__html_message =~ s/\cM\cJ/br()."\n"/eg;
}
$_emailSentType = "";
$mime = MIME::Entity->build(Type => 'multipart/alternative',
Encoding => '-SUGGEST',
From => $__from,
To => $__to,
Subject => $__subject,
'Importance' => $__importance,
"X-Mailer" => "$_co_domain Sendgrid Mailer - Version 2.0",
'X-Organization' => "$_co_name",
"X-Mail-Sent-For" => "The Club or www.$_co_domain/$_un; From IP: $_sendIp",
'X-Priority' => $__xpriority,
'X-MSMail-Priority' => $__x_ms_priority
);
$_sendKey = ""; # removed for security...
$_removeLink = qq~https://www.testing.com/backoffice.cgi?page=unsubscribe$_sendKey~;
$__text_message .= qq~
You are receiving this email as a club member of The $_co_name. You can turn off your
email subscription by logging into your back office with your username and password
that you registered with. Or you may click:
$_removeLink to remove yourself.
~;
if($__html_message) {
$__html_message .= qq~<br>
<br>
<span style="font-size: 12px; color: #808040;">
You are receiving this email as a club member of The $_co_name.<br>
You can turn off your email subscription by logging into your back office<br>
with your username and password that you registered with.<br>
Or you may click: Here to remove yourself,<br>
or call our Customer Care Center at (888)123-4567 for assistance<br>
<br>
<br></span>
<br>
~;
}
$mime->attach(Type => 'text/plain',
Encoding =>'-SUGGEST',
Data => $__text_message);
$mime->attach(Type => 'text/html',
Encoding =>'-SUGGEST',
Data => $__html_message);
if($_attachFile) {
### Attach stuff to it:
if($_attachFilePath && ($_attachFilePath =~ /csv$/i)) {
$_mimType = "text/csv";
$_mimEncoding = "US-ASCII";
} elsif($_attachFilePath && ($_attachFilePath =~ /gif$/i)) {
$_mimType = "image/gif";
$_mimEncoding = "base64";
} elsif($_attachFilePath && ($_attachFilePath =~ /jpg$/i)) {
$_mimType = "images/jpeg";
$_mimEncoding = "base64";
} elsif($_attachFilePath && ($_attachFilePath =~ /png$/i)) {
$_mimType = "images/png";
$_mimEncoding = "base64";
} else {
$_mimType = "text/plain";
$_mimEncoding = "UTF-8";
}
# Attach the file that it sent...
$mime->attach(Path => $_attachFilePath,
Type => "$_mimType",
Encoding => "$_mimEncoding");
}
# Sendgrid Login credentials
$username = 'myloginemail';
$password = "myloginpass";
# Open a connection to the SendGrid mail server
$smtp = Net::SMTP->new('smtp.sendgrid.net',
Port=> 587,
Timeout => 60,
Hello => "testing.com", Debug => 1) or return("0","could not establish connection!: $!");
# Authenticate
if($smtp) {
$smtp->auth($username, $password);
# Send the rest of the SMTP stuff to the server
$smtp->mail($__from);
$smtp->to($__to);
$smtp->data($mime->stringify);
$smtp->quit();
open(DEB,">>/home/path/files/aa_mime_email_debug_tracking.txt");
seek(DEB,0,2);
$_resultMsg = $smtp->message();
$_resultMsg =~ s/\n//eg;
$_resultMsg =~ s/\cM\cJ//eg;
# just added this, not sure if it will work... want to create a loop of the $smtp to put it in the debug file, so I can see what is happening and why email does not go anywhere, but connection works...
$_resultMsg2 = "";
foreach (keys %{$smtp}) {
$_resultMsg2 .= "," if $_resultMsg2;
# Test this one:
$_resultMsg2 .= " $_ => ${$hash_ref}{$_}";
# Then test this one:
$_resultMsg2 .= ", $_ = " . ${$hash_ref}->{$_};
}
print DEB qq~Result: '~ . $_resultMsg . qq~'; smtpTest: '~ . $_resultMsg2 . qq~'; From => "$__from", To => "$__to", Subject => "$__subject", If Member Username passed: "$_mbrUn", on: ~ . Format_Date_For_Viewing(time(),"") . "\n";
close(DEB);
return (1,"");
} else {
open(DEB,">>/home/path/files/aa_mime_email_debug_tracking.txt");
seek(DEB,0,2);
print DEB qq~ERROR: '~ . $smtp->message() . qq~' (Sendgrid error!!!) - From => "$__from", To => "$__to", Subject => "$__subject", If Member Username passed: "$_mbrUn", on: ~ . Format_Date_For_Viewing(time(),"") . "\n";
close(DEB);
return (0,$smtp->message());
}
} else {
# Code for old email system... not using sendgrid, using sendmail... no longer in use, but code left there for times when sendgrid not working or something... used MimeLite
}
}
Anyhow, I have no idea why it is not working. The Server admins checked and there are no errors or no emails in the queue, either... so nothing just stuck somewhere, that we can find...
Can someone see anything, aside from my terrible programming??? lol
Thanks,
-Richard
If the program worked before, did not change, and is not giving any errors, there is probably nothing wrong with it. Test sending the email manually.
Start by encoding your username and password:
perl -MMIME::Base64 -e 'print encode_base64 $_ for qw/myloginemail myloginpass/'
Then use telnet with encoded username after the first 334 and password after the second:
telnet smtp.sendgrid.net 587
Trying 167.89.118.51...
Connected to smtp.sendgrid.net.
Escape character is '^]'.
220 SG ESMTP service ready at ismtpd0011p1las1.sendgrid.net
helo testing.com
250 Hello, nice to meet you
auth login
334 VXNlcm5hbWU6
bXlsb2dpbmVtYWls
334 UGFzc3dvcmQ6
bXlsb2dpbnBhc3M=
235 Authentication succeeded
mail from:<testmailacct#gmail.com>
250 2.1.5 Ok
rcpt to:<testmailacct#gmail.com>
250 2.1.5 Ok
data
354 End data with <CR><LF>.<CR><LF>
subject: test
This is test 0.
.
250 2.0.0 Ok: queued as BBAEA3483C73
quit
221 2.0.0 Bye
Connection closed by foreign host.

connect to localhost failed (Connection refused) no (more) retries

I want to send an email using perl ,but when i execute the command as follows:
#./sendmail.sh "par1" "par2" "par3"
i got the error msg "connect to localhost failed (Connection refused) no (more) retries"
sendmail.sh:
/usr/bin/perl /code/sendmail.pl "$1" "$2" "$3";
sendmail.pl:
#!/usr/bin/perl -w
use Mail::Sendmail;
my $event1 = shift(#ARGV);
my $event2 = shift(#ARGV);
my $time = shift(#ARGV);
#my $info = shift(#ARGV);
my $datetime = `/bin/date "+20%y-%m-%d %H:%M:%S"`;
chomp $datetime;
$msg = "This is Monitor System speak:\n
The system discovers the events at $datetime.
Something may be abnormal, please check it. The detail is below:\n";
$msg = $msg."$event1 and $event2 at $time\n";
$msg = $msg."\n";
$msg = $msg."Any problem, check it from http://map_test.php\n\n\n";
$mail_subject = "Abnormal";
sendmail(
From => 'localhost',
To => 'test#mail.com',
Subject => $mail_subject,
Message => $msg,
);
Any help appreciated.
smtp stands for simple mail transfer protocol.
When you need to send an email your mail client needs to talk to an smtp server which will accept the message. Normally your internet service provider will provide an smtp host. If you look at your mail client it will need to have an smtp server configured to be able to send mail.
Ok so when you install the Mail::Sendmail module, it doesn't know what your smtp server will be. It is up to you to tell it. It provides a default of localhost which would often be true if your server is running a sendmail daemon.
The configuration of Mail::Sendmail is stored in a variable called
%Mail::Sendmail::mailcfg
You can change the value of the sendmail server using this snippet of code:
unshift #{$Mail::Sendmail::mailcfg{'smtp'}} , 'my.smtp.server';
You need to add this line of code to your script to set the smtp server.
It adds this server to an array which also includes localhost.
So if neither of the hosts work it will still print an error message about localhost which is slightly confusing.
If you use Data::Dumper to print the contents of the mailcfg variable it will look something like this:
#!/usr/bin/perl
use Mail::Sendmail;
use Data::Dumper;
unshift #{$Mail::Sendmail::mailcfg{'smtp'}} , 'my.smtp.server';
print Dumper(\%Mail::Sendmail::mailcfg);
Should return:
$VAR1 = {
'retries' => 1,
'smtp' => [
'my.smtp.server',
'localhost'
],
'delay' => 1,
'port' => 25,
'from' => '',
'debug' => 0,
'tz' => '',
'mime' => 1
};

How to fail over

If I use wget to retrieve something from the geonames.org server, it reports two IP addresses, and the first one fails but it gets it from the second:
Resolving ws.geonames.org (ws.geonames.org)... 5.9.41.208, 176.9.107.169
Connecting to ws.geonames.org (ws.geonames.org)|5.9.41.208|:80... failed: Connection refused.
Connecting to ws.geonames.org (ws.geonames.org)|176.9.107.169|:80... connected.
HTTP request sent, awaiting response... 200 OK
But unfortunately I have to access it through perl using LWP::UserAgent and HTTP::Request. How can I make them try the second IP if the first fails?
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(
GET =>
"http://ws.geonames.org/countrySubdivision?lat=$lat&lng=$long&radius=$radius&username=xyzzy");
my $res = $ua->request($req);
You can do it yourself: get all the IP addresses with the help of Net::DNS::Resolver, and then try all IP addresses until you get a successful response. Note that you have to supply the "Host" header yourself if working with an IP address, in case the server is doing name-based virtual hosts.
Something like the following lines could work. Maybe there's even a CPAN module for this, I did not check:
use Net::DNS;
use LWP::UserAgent;
my #addrs;
{
my $res = Net::DNS::Resolver->new;
my $query = $res->search("ws.geonames.org");
if ($query) {
for my $rr ($query->answer) {
if ($rr->type eq "A") {
push #addrs, $rr->address;
}
}
} else {
die "DNS query failed: ", $res->errorstring, "\n";
}
}
my $ua = LWP::UserAgent->new;
my $res;
for my $addr (#addrs) {
$res = $ua->get("http://$addr/countrySubdivision?lat=$lat&lng=$long&radius=$radius&username=xyzzy", Host => 'ws.geonames.org');
last if $res->is_success;
}
The solution from Slaven is OK except when the IP addresses are not directly accessible.
In that case, the following works for me:
local #LWP::Protocol::http::EXTRA_SOCK_OPTS = (
PeerAddr => 'my_hostname',
MultiHomed => 1,
);
my $response = $ua->post('https://my_hostname/...', ...);

Perl: Unable to check validity of hostname for Net::Appliance::Session

When I tried to pass an invalid hostname, the code will get into an infinite loop.
my $s = Net::Appliance::Session->new({
personality => 'ios',
transport => 'SSH',
host => $ip
});
Is there a way to overcome this bug?
EDIT:
Here's my full code:
I use the subroutine to download the config file of my network device. When I pass in an invalid IP address in download_config, it will get into an infinite loop.
sub download_config
{
my ($ip) = #_;
my $s = Net::Appliance::Session->new({
personality => 'ios',
transport => 'SSH',
host => $ip,
Timeout => 1
});
$s->set_global_log_at('debug'); # maximum debugging
eval {
$s->connect({ username => $username, password => $password });
$s->begin_privileged({ password => $enable_password });
#get hostname to set the file name
$hostname_result = $s->cmd('sh run | inc hostname');
$hostname_result =~ m/hostname (.*)/;
$hostname = $1;
#download the file
my #running_config = $s->cmd('sh run');
#running_config = #running_config[ 2 .. (#running_config -1)];#remove header and footer of the file
open(FH, "> temp/".$hostname.".txt") or die("Cannot open config file : $!");
print FH #running_config;
close FH;
$s->end_privileged;
};
if ($#) {
#when the login details are wrong
print redirect('../../na/unauthorised.html');
}
$s->close;
}
The developer has fixed the bug.
Are you sure?
Are you tried this example code with your host name?
http://cpansearch.perl.org/src/OLIVER/Net-Appliance-Session-3.120560/examples/example-1.pl
If yes, you could create an RT ticket or you could try to contact the author.
I have chacked the code, and did not found anything (too) nasty.
Regards,

Why does Perl's Net::Msmgr hang when I try to authenticate?

There's Net::Msmgr module on CPAN. It's written clean and the code looks trustworthy at the first glance. However this module seems to be beta and there is little documentation and no tests :-/
Has anyone used this module in production? I haven't managed to make it run by now, because it requires all event loop processing to be done in the application and as I've already said there is little documentation and no working examples to study.
That's where I've gone so far:
#!/usr/bin/perl
use strict;
use warnings;
use Event;
use Net::Msmgr::Object;
use Net::Msmgr::Session;
use Net::Msmgr::User;
use constant DEBUG => 511;
use constant EVENT_TIMEOUT => 5; # seconds
my ($username, $password) = qw/my.username#live.com my.password/;
my $buddy = 'your.username#live.com';
my $user = Net::Msmgr::User->new(user => $username, password => $password);
my $session = Net::Msmgr::Session->new;
$session->debug(DEBUG);
$session->login_handler(\&login_handler);
$session->user($user);
my $conv;
sub login_handler {
my $self = shift;
print "LOGIN\n";
$self->ui_state_nln;
$conv = $session->ui_new_conversation;
$conv->invite($buddy);
}
our %watcher;
sub ConnectHandler {
my ($connection) = #_;
warn "CONNECT\n";
my $socket = $connection->socket;
$watcher{$connection} = Event->io(fd => $socket,
cb => [ $connection, '_recv_message' ],
poll => 're',
desc => 'recv_watcher',
repeat => 1);
}
sub DisconnectHandler {
my $connection = shift;
print "DISCONNECT\n";
$watcher{$connection}->cancel;
}
$session->connect_handler(\&ConnectHandler);
$session->disconnect_handler(\&DisconnectHandler);
$session->Login;
Event::loop();
That's what it outputs:
Dispatch Server connecting to: messenger.hotmail.com:1863
Dispatch Server connected
CONNECT
Dispatch Server >>>VER 1 MSNP2 CVR0
--> VER 1 MSNP2 CVR0
Dispatch Server >>>USR 2 MD5 I my.username#live.com
--> USR 2 MD5 I my.username#live.com
Dispatch Server <<<VER 1 CVR0
<-- VER 1 CVR0
And that's all, here it hangs. The handler on login is not being triggered. What am I doing wrong?
Hope these documents will help you out
1) Net::Msmgr documentation
2) Net::Msmgr::Session