the first IP of the next block with Net::IP - perl

i am trying to use Net::IP module from cpan
my $block = new Net::IP('194.158.1.0/24');
$block->ip() # get the first ip on the block
$block->last_ip() #get the last ip on the block
how can i increment the last ip , as i want to know the first ip on the next block
i tried something like :
++$block->last_ip()
but this is not working any idea?

You can't increment the last ip as mentioned in Net::IP document.
The ++ operator returns undef when the last address of the range is reached.
The most simple way is to convert the last ip into integer, increment, then create a brand new Net::IP object from it.
#!/usr/bin/perl
use strict;
use warnings;
use Net::IP qw(ip_inttobin ip_bintoip);
my $block = Net::IP->new('194.158.1.0/24');
my $next_bin = ip_inttobin($block->last_int + 1, $block->version);
my $next = Net::IP->new(ip_bintoip($next_bin, $block->version));
print $next->ip;

Related

Reversing the IP address in Linux using perl

I have a job where I need to do nslookup on an IP address. If it matches then I need to print the name of the host. The problem is that the IP address comes reversed when running the command.
nslookup 10.11.12.13
13.12.11.10.in-addr.arpa
I tried to use reverse but that reversed everything which is not what I want.
my $ip = '13.12.11.10';
$result = reverse($ip);
print $result;
which then prints 01.11.21.31
I do not want to reverse everything, just the full numbers.
Please can someone help?
Simply split the IP address on .s using split, reverse the resulting array, then rejoin it:
join(".", reverse(split(/\./, $ip)))
This will give you the "reversed" IP address, which you can then compare to the nslookup result.
So what we need to do is to just split the actual address, reorder them in reverse and then match the IP to the reversed IP.
use strict;
use warnings;
my $ipaddress = '10.11.12.13';
my #ip = split /\./,$ipaddress; #split the IP by .
my $sserddapi = "$ip[3].$ip[2].$ip[1].$ip[0]"; #reverse it
my #lookup = `nslookup $ipaddress`; #do the match
$lookup[3] =~ s/\s+//g; #remove all whitespace
my #device = split /=/, $lookup[3]; #get the hostname
if ($lookup[3] =~ /^$sserddapi/) { #see if it matches
$lookup[3] =~ s/$sserddapi.in-addr.arpaname=//g; #Remove the unwanted stuff
print "$ipaddress = $lookup[3]\n"; #print the result
}

How to take IP address as input

How to take IP address as input and use it in the Xpath expressions?
When i am using it as a static input like $iptext = '10.109.25.1'; it is working fine but when i am getting the input from user i am getting error
#my $ip = <>;
#my $iptext=$ip.'';
my $query = "//nodeA/nodeB[nodeC/text() = '$iptext']/../NodeD/Name/text()";
I assume what you are forgetting is that input read with <> or <STDIN> come with newlines:
chomp(my $ip = <>); # newline removed
Documentation for chomp here.
If you do not remove the newline, your $query string will contain that newline, which I assume you pass to Xpath or some such:
xpath //nodeA/nodeB[nodeC/text() = '10.109.25.1
']/../NodeD/Name/text()
And of course that does not work.

Getting all hostnames from IP address in Perl

I'm trying to find a way to get all hostnames that resolve to an IP address.
The gethostbyaddr function appears to only retrieve the first record from DNS (no matter if it's in scalar or list context).
Example:
my $hostname = gethostbyaddr(inet_aton($ip_to_check), AF_INET);
$print($hostname); //output: joe.example.com
my #hostnames = gethostbyaddr(inet_aton($ip_to_check), AF_INET);
foreach my $hostname (#hostnames){
print "(", join(',',#hostnames), ")"; //output: (joe.example.com,,2,4,?)
}
From the terminal:
$ host 192.168.1.5
5.1.168.192.in-addr.arpa domain name pointer joe.example.com.
5.1.168.192.in-addr.arpa domain name pointer john.example.com.
I've heard that Net::DNS is a little more robust, but I haven't had any luck getting that to pull all entries as well.
I used a combination of answers given here and elsewhere on stack overflow to find the answer I was looking for.
# create new Resolver Object
my $res = Net::DNS::Resolver->new;
# change IP from 192.168.1.15 to 15.1.168.192.in-addr.arpa for searching
my $target_IP = join('.', reverse split(/\./, $ip_to_check)).".in-addr.arpa";
# query DNS
my $query = $res->query("$target_IP", "PTR");
# if a result is found
if ($query){
print("Resolves to:\n");
# for every result, print the IP address
foreach my $rr ($query->answer){
# show all unless the type is PTR (pointer to a canonical name)
next unless $rr->type eq "PTR";
# remove the period at the end
printf(substr($rr->rdatastr, 0, -1));
}
}
The gethostby... interface is quite old and clunky, being defined back in primeval times before Perl got references and pretensions to OO. And it doesn't work the way you're trying to use it. When used in list context, it returns the primary name as the first element and a space-separated(!) list of aliases as the second:
my ($hostname, $aliases) = gethostbyaddr($addr, AF_INET);
my #hostname = ($hostname, split ' ', $aliases);
say join ' ', #hostname;
Now that's the theory; I didn't locate any IP addresses with multiple PTR records offhand, so I can't test if gethostbyaddr will actually return them -- it probably depends on your underlying C runtime as well -- but it does work if you use gethostbyname with a CNAMEd name, for instance.
Here's a small program I use to lookup all PTR records for a netmask (for example 192.0.2.0/28 ) when doing abuse tracking tasks. It sends up to 15 queries a second and when they are all sent then starts reading the responses (so it'd need a little work to function properly for bigger net blocks).
#!/usr/bin/env perl
use strict;
use warnings;
use Net::Netmask;
use Net::DNS;
#ARGV or die "$0 ip/cidr\n";
my $block = Net::Netmask->new(shift);
my $res = Net::DNS::Resolver->new;
my %sockets;
my $i = 0;
for my $i (1 .. $block->size - 1) {
my $ip = $block->nth($i);
my $reverse_ip = join ".", reverse split m/\./, $ip;
$reverse_ip .= ".in-addr.arpa";
#print "$ip\n";
my $bgsock = $res->bgsend($reverse_ip, 'PTR');
$sockets{$ip} = $bgsock;
sleep 1 unless $i % 15;
}
$i = 0;
for my $i (1 .. $block->size - 1) {
my $ip = $block->nth($i);
my $socket = $sockets{$ip};
my $wait = 0;
until ($res->bgisready($socket)) {
print "waiting for $ip\n" if $wait > 0;
sleep 1 + $wait;
$wait++;
}
my $packet = $res->bgread($socket);
my #rr = $packet->answer;
printf "%-15s %s\n", $ip, $res->errorstring
unless #rr;
for my $rr (#rr) {
printf "%-15s %s\n", $ip, $rr->string;
}
}
I don't think this is a well-formed problem statement. In the general case, there's a nearly infinite number of DNS names that could resolve to any IP address, even unknown to the party that holds the address. Reverse-lookups are fundamentally unreliable, and are not capable of answering the question the poster would like, since all names for an IP do not need to be in the visible reverse map.
The first answer, which enumerates the reverse map, is the best one can do, but it will miss any names that have not been entered in the map.
This is what I have used:
sub getauthoritivename
{
my ($printerdns)=#_;
my $res = Net::DNS::Resolver->new(searchlist=>$config->{searchlist});
my $query = $res->search($printerdns);
if ($query)
{
foreach my $rr ($query->answer)
{
next unless $rr->type eq "A";
print $rr->name;
}
}
else
{
warn "query failed: ", $res->errorstring, "\n";
return 0;
}
}
As long as $rr->name finds names, it keeps adding them.

Mechanize example - quiete simple but too complex for me: need explanations

Good day dear community. I am new to programming. And i want to digg deeper into Perl.
So i have a Mechanize example - quiete simple but too complex for me: need explanations. I need your help here with this!
use strict;
$|++;
use WWW::Mechanize;
use File::Basename;
my $m = WWW::Mechanize->new;
$m->get("http://www.despair.com/indem.html");
my #top_links = #{$m->links};
for my $top_link_num (0..$#top_links) {
next unless $top_links[$top_link_num][0] =~ /^http:/;
$m->follow_link( n=>$top_link_num ) or die "can't follow $top_link_num";
print $m->uri, "\n";
for my $image (grep m{^http://store4}, map $_->[0], #{$m->links}) {
my $local = basename $image;
print " $image...", $m->mirror($image, $local)->message, "\n"
}
$m->back or die "can't go back";
}
can anybody give me a line by line explanation?
I tried the first coupe of lines.
However you need to make sure to first read and understand the following documentation:
1) Perl Intro - especially variable scoping part
2) Perl data
3) Perl Data Structures Cookbook
P.S. As Eric said in the comment, this code is definitely NOT a very good example for someone just starting. It's got way too many non-trivial ideas/concepts/moving parts.
use strict;
# Does not allow undeclared global variables or other unsafe constructs.
# You should ALWAYS code with "use strict; use warnings"
# See http://perldoc.perl.org/strict.html
$|++;
# Turn on autoflush on STDOUT filehandle.
# See "http://perldoc.perl.org/perlvar.html" for "$|" and other special variables.
# P.S. This "++" is a hack - it would be a lot more readable to do "$| = 1;"
# since $| only cares whether the value is zero or non-zero.
use WWW::Mechanize; # Load the module for getting web sites.
use File::Basename; # Load the module for finding script's name/path.
my $m = WWW::Mechanize->new; # Create new object via a constructor (new)
$m->get("http://www.despair.com/indem.html");
# Retrieve the contents of the URL.
# See http://search.cpan.org/dist/WWW-Mechanize/lib/WWW/Mechanize.pm
# for the module's documentation (aka POD)
my #top_links = #{$m->links};
# Declare a "#top_links" array,
# get the list of links on the above page (returns array reference)
# and de-reference that array reference and store it in #top_links array
for my $top_link_num (0..$#top_links) {
# Loop over all integers between 0 and the last index of #top_links array
# (e.g. if there were 3 links, loop over 0,1,2
# Assign the current loop value to $top_link_num variable
next unless $top_links[$top_link_num][0] =~ /^http:/;
# go to next iteration of the loop unless the current link's URL is HTTP protocol
# Current link is the element of the array with current undex -
# $top_links[$top_link_num]
# The link data is stored as an array reference,
# with the link URL being the first element of the arrayref
# Therefore, $top_links[$top_link_num][0] - which is the shorthand
# for $top_links[$top_link_num]->[0] as you learned
# from reading Data Structures Cookbook I linked - is the URL
# To check if URL is HTTP prtocol, we check if it starts with http:
# via regular expression - see "http://perldoc.perl.org/perlre.html"
$m->follow_link( n=>$top_link_num ) or die "can't follow $top_link_num";
print $m->uri, "\n";
for my $image (grep m{^http://store4}, map $_->[0], #{$m->links}) {
my $local = basename $image;
print " $image...", $m->mirror($image, $local)->message, "\n"
}
$m->back or die "can't go back";
}

Reverse DNS lookup in perl

How do I perform a reverse DNS lookup, that is how do I resolve an IP address to its DNS hostname in Perl?
If you need more detailed DNS info use the Net::DNS module, here is an example:
use Net::DNS;
my $res = Net::DNS::Resolver->new;
# create the reverse lookup DNS name (note that the octets in the IP address need to be reversed).
my $IP = "209.85.173.103";
my $target_IP = join('.', reverse split(/\./, $IP)).".in-addr.arpa";
my $query = $res->query("$target_IP", "PTR");
if ($query) {
foreach my $rr ($query->answer) {
next unless $rr->type eq "PTR";
print $rr->rdatastr, "\n";
}
} else {
warn "query failed: ", $res->errorstring, "\n";
}
Original Source EliteHackers.info, more details there as well.
gethostbyaddr and similar calls. See http://perldoc.perl.org/functions/gethostbyaddr.html
use Socket;
$iaddr = inet_aton("127.0.0.1"); # or whatever address
$name = gethostbyaddr($iaddr, AF_INET);
perl -MSocket -E 'say scalar gethostbyaddr(inet_aton("69.89.27.250"), AF_INET)'
Returns: Can't find string terminator "'" anywhere before EOF at -e line 1.
perl -MSocket -E "say scalar gethostbyaddr(inet_aton(\"69.89.27.250\"), AF_INET)"
Returns: box250.bluehost.com
I have to change the line to use double quotes and then escape out the quotes around the IP address
one-liner:
perl -MSocket -E 'say scalar gethostbyaddr(inet_aton("79.81.152.79"), AF_INET)'
There may be an easier way, but for IPv4, if you can perform ordinary DNS lookups, you can always construct the reverse query yourself. For the IPv4 address A.B.C.D, look up any PTR records at D.C.B.A.in-addr.arpa. For IPv6, you take the 128 hex nibbles and flip them around and append ipv6.arpa. and do the same thing.
If gethostbyaddr doesn't fit your needs, Net::DNS is more flexible.
This might be useful...
$ip = "XXX.XXX.XXX.XXX" # IPV4 address.
my #numbers = split (/\./, $ip);
if (scalar(#numbers) != 4)
{
print "$ip is not a valid IP address.\n";
next;
}
my $ip_addr = pack("C4", #numbers);
# First element of the array returned by gethostbyaddr is host name.
my ($name) = (gethostbyaddr($ip_addr, 2))[0];