How do I output error for DNS resolve in Perl? - perl

I have currently a DNS Reverse lookup script which works however there is a small little issue of the script being able to output the DNS system errors.
The problems goes like this:
User keys in false/wrong internet address name etc. "www.whyisthednsnothappening.com"
The script would then clear the screen using system(clear)
The script would then print "can't resolve DNS. The error is due to: various System error"
The script re directs the user back to the same menu/script to type in the name address again.
So the main problem is now step 3 which the script only shows me "Can't resolve DNS. The error is due to: BLANK " Which BLANK is suppose to show errors like "Bad arg length for Socket::inet_ntoa, length is 0, should be 4 at ./showdns.pl line 28, <> line 1." and the menu of the DNS script is located below of the error print.
The Codes:
#!/usr/bin/perl
use IO::Socket;
use warnings;
use strict;
use Term::ANSIColor;
use Socket;
use Sys::Hostname;
print "\nYou are now in Show DNS IP Address!\n\n";
print "*************\n";
print "|DNS Address|\n";
print "*************\n";
print "\nPlease enter a hostname that you wish to view\n\n";
print "\n\nEnter the hostname of Choice Here: ";
my $userchoice = <>;
chomp ($userchoice);
my $hostname = $userchoice;
my $i_addr = scalar(gethostbyname($hostname || 'localhost'));
if ( ! defined $i_addr ) {
my $err = $!;
my $herr = int herror(const char *s);
system('clear');
print("Can't resolve $hostname: $herr, try again");
exec("/root/Desktop/showdns.pl");
exit();
}
my $name = inet_ntoa($i_addr);
my $coloredText = colored($name, 'bold underline blue');
print "\n\nThe hostname IP address is: $coloredText\n\n";
print "Press enter to go back to the main menu\n\n";
my $userinput2 = <>;
chomp ($userinput2);
system("clear");
system("/root/Desktop/simpleip.pl");
Can someone please give advice on the codes? Thanks!

Ah, I see what you mean. The system("clear") call is clearing the $! variable before you have a chance to print the error from gethostbyname.
my $i_addr = scalar(gethostbyname($hostname || 'localhost'));
if ( ! defined $i_addr ) {
my $err = $!;
system("clear");
print("Can't resolve $hostname: $err, try again");
system("/root/Desktop/showdns.pl");
exit();
}
Though as far as I can tell, the particular error gethostbyname returns isn't very meaningful.
You may want to look into putting a loop in your script instead of having it start over using system(). You certainly don't want to continue on to inet_ntoa if there was a failure. Note that inet_ntoa doesn't have anything to do with a DNS lookup; that's done by gethostbyname. inet_ntoa just changes a 4-byte string into the normal 123.123.123.123
printable form of an ipaddress. sprintf("%vd", $i_addr) does the same thing.

Two additional questions:
If you remove the call to
system('clear') Does the error
from gethostbyname get displayed
then?
Why do you use
system('/root/Desktop/showdns.pl')
To call the same script recursively?
Wouldn't it be better to use exec
instead of system? exec terminates
the current process. while system
forks of an entire new process and
waits for that process to exit. So
if your users enter, for example, 20
invalid hostnames, you'll end up
with 20 processes just waiting for
the one that was most recently
created.
Gr,
ldx

Please check the following to resolve the above "dns" issues in perl script.
As DNS server is not running, perl will not resolve the address. so it returns an empty string and inet_ntoa will throw error for that empty string.
If you are using a linux system please verify the following:
a) Check the internet address in the file /etc/resolv.conf
nameserver 172.19.1.11 (IP address of your internet or survice provider)
b) Add "dns" in the /etc/nsswitch.conf file as follows:
hosts: files dns

Related

nslookup script to loop through IP addresses in perl

Stackoverflow community,
I am bran new to PERL scripting and need help [part of this script was from an internet source] to do an nslookup on a list of IP addresses in a file and loop through each one until I get to the end. If the domain name does not exist then do X, if it does do Y.
information for the below :
-existent - is a key word when nslookup aborts
name - is a key word when it works
listofhosts - is my ip address list
Thank you any help is greatly appreciated
#!/usr/bin/perl
#!c:\perl64\bin
use strict;
use warnings;
my $noname=-existent;
my $name=name;
open IPADDRESSES,("c:\\perl64\\scripts\\listofhosts.txt") or die("File could not be opened :$!");
my #list=<IPADDRESSES>;
foreach my $list(#list);
my $results=`nslookup $list`;
CHOMP ($list);
if ($noname) {
print ("no name")}
elsif ($name){
print ("IP address $list:\n");
print ("=\n");
print ("DNS name:$results\n");
}
close (IPADDRESSES);
Also try looking at Net::Nslookup instead of using nslookup ...

Perl read line string without trailing newline

Very new to perl and have been stuck for quite awhile on this.
If I change the variable from READSTDIN to google.com, it says google.com is online as it should. If I use the STDIN and input google.com and print $host it prints google.com, however in the ping it doesn't work.
Sample output:
perl perl.pl
What is the website that is offline or displaying an error?google.com
Warning: google.com
appears to be down or icmp packets are blocked by their server
Code:
use strict;
use warnings;
use Net::Ping;
#optionally specify a timeout in seconds (Defaults to 5 if not set)
my $timeout = 10;
# Create a new ping object
my $p = Net::Ping->new("icmp");
#Domain variable
print "What is the website that is offline or displaying an error?";
my $host = readline STDIN;
# perform the ping
if ( $p->ping( $host, $timeout ) ) {
print "Host $host is alive\n";
} else {
print "Warning: $host appears to be down or icmp packets are blocked by their server\n";
}
# close our ping handle
$p->close();
If I change the variable from READSTDIN to google.com, it says google.com is online as it should. If I use the STDIN and input google.com and print $host it prints google.com, however in the ping it doesn't work. I appreciate anyone who can help me at all!
Note the newline in your input:
perl perl.pl
What is the website that is offline or displaying an error?google.com
Warning: google.com <--- newline after google.com puts the rest of the output on the next line...
appears to be down or icmp packets are blocked by their server
You should be using chomp to remove the newline from your input:
chomp( my $host = readline STDIN );
Or more simply:
chomp( my $host = <STDIN> ); # same thing as above

Weird issue with Net::SSH::Expect in Perl script

I am working on putting together a perl script. I have captured it below:
#!/usr/bin/perl
use Tie::File;
use Net::SSH::Expect;
use utf8;
use warnings;
use diagnostics;
# Grab password from hidden file
$pw=`cat .password`;
chomp $pw;
#Read list of 9200's from hosts.list file into an array
tie #hosts, 'Tie::File', "hosts.list" or die;
#Loop through hosts, connect via ssh, run commands, and write out log files.
foreach (#hosts) {
#Create ssh session handle
my $ssh = Net::SSH::Expect->new (
host => $_,
password => $pw,
user => 'user',
raw_pty => 1
);
my $login_output = $ssh->login();
if ($login_output !~ /.*sbc.*>/) {
die "Login failed. Login output was $login_output";
}
$ssh->send("show sip errors");
my $line;
while ( defined ($line = $ssh->read_line()) ){
print $line . "\n";
}
$ssh->close();
}
First, I'm not a programmer, so style is probably very ugly. Sorry about that :) The goal is to run several commands on a remote appliance, capture the results in separate files, which will then be consumed by a 3rd party parsing engine (splunk).
The current implemented functionality is able to log in to remote hosts, run the command, and then print out to stdout. Not quite there, but still shows a good proof of concept.
The script runs fine for the first 3 hosts in the hosts.list file. However as soon as it gets to the fourth host, I receive this exception:
Uncaught exception from user code:
SSHAuthenticationError Login timed out. The input stream currently has the contents bellow: user#myhost.mydomain's password: at /System/Library/Perl/Extras/5.12/Expect.pm line 828
at /Library/Perl/5.12/Net/SSH/Expect.pm line 209
Net::SSH::Expect::__ANON__('ARRAY(0x7fd718a03008)') called at /System/Library/Perl/Extras/5.12/Expect.pm line 828
Expect::_multi_expect(1, 'ARRAY(0x7fd7189fbce8)', 'ARRAY(0x7fd7189f7460)') called at /System/Library/Perl/Extras/5.12/Expect.pm line 565
Expect::expect('Expect=GLOB(0x7fd7189f1878)', 1, 'ARRAY(0x7fd718a01530)', 'ARRAY(0x7fd7189f15a8)', 'ARRAY(0x7fd71890a3d0)', 'ARRAY(0x7fd718a07470)', 'ARRAY(0x7fd7189d8b18)') called at /Library/Perl/5.12/Net/SSH/Expect.pm line 580
Net::SSH::Expect::_sec_expect('Net::SSH::Expect=HASH(0x7fd718a29828)', 1, 'ARRAY(0x7fd718a01530)', 'ARRAY(0x7fd7189f15a8)', 'ARRAY(0x7fd71890a3d0)', 'ARRAY(0x7fd718a07470)', 'ARRAY(0x7fd7189d8b18)') called at /Library/Perl/5.12/Net/SSH/Expect.pm line 213
Net::SSH::Expect::login('Net::SSH::Expect=HASH(0x7fd718a29828)') called at ./pcscfFetch.pl line 26
Any ideas on what the problem could be? I am able to log in to the host with no issue manually via ssh. The script works fine for our other hosts, it's just this one outlier that I can't seem to figure out. Any advice would be appreciated. Thanks!
I did end up resolving this. In the constructor for $ssh I set the timeout to 10 seconds, instead of the default 1. The script runs significantly slower, but I don't appear to have the issues I was running into before. Appreciate the feedback!
Net::SSH::Expect is not reliable.
Use Net::OpenSSH instead, or if you want to run the same set of commands in several hosts Net::OpenSSH::Parallel.

How to run SSH commands using Net::SSH::Perl?

I don't know if I managed to install Net::SSH::Perl module successfully but I can't seem to be able to run the following code:
my $ssh = Net::SSH::Perl->new($remote_host);
$ssh->login($username, $password);
print "login done", "\n";
my ($out, $err, $exit) = $ssh->cmd($cmd);
print "$out", "\n";
I am able to login but cannot print the $out. I keep getting this error:
Use of uninitialized value $out in string at test_ssh.pl line 28.
Line 28 refers to print "$out", "\n";.
I am running this code on Cygwin. What should I do now?
EDIT:
I got the following error msg when I ran my $ssh = Net::SSH::Perl->new($remote_host, options => ["Debug yes"]);:
Use of uninitialized value $out in string at test_ssh.pl line 29 (#1)
(W uninitialized) An undefined value was used as if it were already
defined. It was interpreted as a "" or a 0, but maybe it was a mistake.
To suppress this warning assign a defined value to your variables.
To help you figure out what was undefined, perl will try to tell you the
name of the variable (if any) that was undefined. In some cases it cannot
do this, so it also tells you what operation you used the undefined value
in. Note, however, that perl optimizes your program and the operation
displayed in the warning may not necessarily appear literally in your
program. For example, "that $foo" is usually optimized into "that "
. $foo, and the warning will refer to the concatenation (.) operator,
even though there is no . in your program.
EDIT2:
Here's my full code
use strict;
use warnings;
use Net::SSH::Perl;
my $remote_host = '<host ip address>';
my $password = 'pass';
my $username = 'user';
my $cmd = 'copy run tftp:<my own ip address>';
warn "Starting SSH Services:...";
my $ssh = Net::SSH::Perl->new($remote_host, debug => 1);
print "done", "\n";
warn "Starting Login:...";
$ssh->login($username, $password);
print "login done", "\n";
warn "Starting command:...";
#$ssh->cmd($cmd);
#my($stdout, $stderr, $exit) = $ssh->cmd($cmd);
my ($out, $err, $exit) = $ssh->cmd($cmd);
print "$out", "\n";
The error message on "print "$out","\n";" line:
<Computername>: channel 1: new [client-session]
<Computername>: Requesting channel_open for channel 1.
<Computername>: Entering interactive session.
<Computername>: Channel open failure: 1: reason 4:
Use of uninitialized value $out in string at test_ssh.pl line 29.
LAST EDIT: I decided to use Net::Appliance::Session to login via SSH to the network devices instead. it's a lot easier to use than Net::SSH::Perl.
Please show more of your code. What is the value of $cmd?
Note that the login method doesn't perform a login: it merely stores the username and password to be used when the connection is set up for each cmd call.
The correct way of enabling debugging messages is
my $ssh = Net::SSH::Perl->new($remote_host, debug => 1);
This will give you trace information from the cmd method which should say, amongst other things
Sending command: xxx
Entering interactive session.
and should give you some clues about what is going wrong.
Your debug output shows the problem. Looking at SSH2.h, open failure reason 4 is SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED. Your username and password are incorrect.
Net::SSH::Perl does support login via username/password, I have a working example, I just got this to work. I used the code from above and took out the Double Quotes (" ") and used single quotes (' ') instead. And "debug => 1" works for debugging the code when having issues. It will display info to you when you try to login if the debug option is set.
I am connecting to a Win32-OpenSSH SSHD server based on Windows Powershell very similar to BSDLinux SSHD server with SFTP support. Supports same Linux style based connection.
I have been trying all other SSH modules all day. Hopefully someone can use this code to just run a command and get the output if required.
You can install Net::SSH::Perl with "cpan -i module-name"
use Net::SSH::Perl;
my $host = 'testmachine.acme.local'; #Or just IP Address
my $user = 'domain\username'; #Or just username
my $pass = 'Password#123';
my $cmd = 'dir C:\\Windows\\';
use Net::SSH::Perl;
my $ssh = Net::SSH::Perl->new($host, debug => 1);
$ssh->login($user, $pass);
my ($out, $err, $exit) = $ssh->cmd($cmd);
print "$out", "\n";
Net::SSH::Perl does not support login via username/password only via interactive password entry or public key. See this post for more information.
http://www.perlmonks.org/?node_id=590452

Inappropriate ioctl for device when changing egid in perl

I have a perl script that is executed by the Jenkins CI, but when it tries to execute the following code i get a "Inappropriate ioctl for device" error.
$) = $new_group;
if($!){
print STDERR $! . "\n";
print STDERR "Failure to change permissions to: Gid: $new_group \n";
next;
}
$> = $new_user;
if($!){
print STDERR $! . "\n";
print STDERR "Failure to change permissions to: Uid: $new_user \n";
next;
}
But while if a do the same manually like this, i receive no error
perl -e '$) = 99; if($!){print $! ."\n";} $> = 99; if($!){print $!."\n";}print `whoami`;'
Any clues why this error occures, and what i means? I have search the net, but it seems to occur when filehandlers are open, havnt seen any examples on it occuring when changing users.
All scripts are executed as root.
$! is only useful directly after a failed system call. When setting the group or user is successful, you don't really know what will be in $!, and can't rely on it being a false value. You might trying using 'or die ' when setting the user and group, or maybe just comparing $) and $> to $new_group and $new_user again after you attempt to set them.
To debug the code, use this method, and see whats going on. Print out each variable content when you receive an error. Please use strict and warnings, they heelp you a lot!
Please include the output if you cannot solve this problem with this method.
use strict;
use warnings;
use Data::Dumper;
$) = $new_group;
warn "\$), \$new_group: ".Dumper($),$new_group);
...