Back to the main page

NIS netgroup cleaning

It.s most likely you have worked with netgroup file if you have any experience with NIS. During the time, this file is probably full with hosts that are out of service, or there are some typos and hosts even do not exist.

It.s good idea to occasionally check the netgroup file and find out if hosts are registered in DNS (both forward and reverse zone) and if they are ping-able at all.

Here is the Perl script that does this. It uses two modules: Note on installing Perl module: You can edit and improve the script, but basically here the netgroup file is taken from NIS and placed is same location as script. Since file can contain IP also, script divides hostnames and IP in two separate files. Host are then checked for A and PTR record and if records matches the host is pinged. Results are in files netgroup.problem.dns, netgroup.problem.ping and netgroup.ok

In case of aliases, the DNS reverse resolution does not match with forward one, but script should handle this with screen messages like:

----------- maya.domain.ca
ALIAS: maya.domain.ca
IP: 192.168.80.3
REALNAME: alex.domain.ca
PING OK: alex.domain.ca

In case of real reverse resolution problem, screen message is:

----------- raven.domain.ca
ORIG: raven.domain.com
IP: 192.168.1.105
PTR_Problem: raven.domain.ca differs from resolved IP (served.domain.ca)

If everything is okay, screen message is:

----------- host1.domain.ca
ORIG: host1.domain.ca
IP: 192.168.80.50
PTR_Resolv: host1.domain.ca
PING OK: host1.domain.ca

And the script is
#!/opt/csw/bin/perl
#
use warnings;
use strict;

# -------- USED PERL MODILES
use Net::Nslookup; #http://search.cpan.org/~darren/Net-Nslookup-2.01/lib/Net/Nslookup.pm
use Net::Ping;   # http://search.cpan.org/~smpeters/Net-Ping-2.36/lib/Net/Ping.pm

# ---------- GET SORTED LIST OF HOSTS FROM netgroup FILE

# define files
my $netgroup = "netgroup.nis"; # example: file nis-master:/var/yp/src/netgroup
my $netgrouponlyip = "netgroup-only-ip"; # file has only IPs taken from netgroup.nis
my $netgrouponlyhostname = "netgroup-only-hostname"; # file has only hostnames taken from netgroup.nis

# open file for reading
open (NG, "< $netgroup") or die "Can't open file $netgroup: $!" ; #open file for reading
my @netgroup = <NG>; # store file in array
close (NG) or die "Can't close file $netgroup: $!" ; # and close the file
# open file for writing
open (LH, "> hosts.list") or die "Can't open hosts.list: $!";

foreach my $netgroup (@netgroup)
{
        # remove comments, blank lines, lines without hosts (there is no user, domain in netgroup file)
        # store lines as array, in scalar context grep returns number of times expresion is true
        my @line = grep !/^#|^$/, grep /\(.*,,\)/, $netgroup;

        # $line is scalar, list of hosts in one line
        foreach my $line (@line)
        {
                # select lines with hosts, ignore lines with only netgroups
                $line =~ s/\(//g;
                $line =~ s/,,\)//g;
                # remove netgroup name
                $line =~ s/^\S+\s+// ; #\S any nonwhitespace character
                $line =~ s/\s+/\n/g ; # replace whitespace with new line
                print LH "$line" ;
        }
}
close LH or die "Can't close hosts.list: $!";

# sort hostnames
open (LH, "< hosts.list") or die "Can't open hosts.list: $!";
open (SLH, "> sort.hosts.list") or die "Can't open sort.hosts.list: $!";
my @hostlines = <LH>;
@hostlines = sort(@hostlines);
foreach my $hostline (@hostlines)
{
        print SLH "$hostline";
}
close(LH) or die "Can't close hosts.list: $!";
close(SLH) or die "Can't close sort.hosts.list: $!";
rename("hosts.list", "hosts.list.orig");
rename("sort.hosts.list", "hosts.list");

# ---------- DEVIDE netgroup FILE TO netgroup-only-ip AND netgroup-only-hostname

open (HOSTL, "< hosts.list") or die "Can't open hosts.list: $!";
my @ipline = <HOSTL>;
close HOSTL or die "Can't close hosts.list: $!";

open (IP, "> $netgrouponlyip") or die "Can't open file $netgrouponlyip: $!";
open (NOIP, "> $netgrouponlyhostname") or die "Can't open file $netgrouponlyhostname: $!";
foreach my $ipline (@ipline)
{
        if ( $ipline =~ m/^\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b$/ )
        {
        print IP "$ipline";
        }
        else
        {
        print NOIP "$ipline";
        }
}
close IP or die "Can't close $netgrouponlyip: $!";
print "File $netgrouponlyip created - contains only IP from netgroup. \n" ;

close NOIP or die "Can't close $netgrouponlyhostname: $!";
print "File $netgrouponlyhostname created - contains only hostnames from netgroup. \n" ;

# -------------- CHECK DNS/PING AND CREATE FILES netgroup.problem.dns, netgroup.problem.ping, netgroup.ok

open (LH, "< $netgrouponlyhostname") or die "Can't open file $netgrouponlyhostname: $!";
my @machines = <LH>; # store file in array and close file
close (LH) or die "Can't close file $netgrouponlyhostname: $!";

open (DNSPROBLEM, "> netgroup.problem.dns")     or die "Can't open netgroup.problem.dns: $!";
open (PINGPROBLEM, "> netgroup.problem.ping")   or die "Can't open netgroup.problem.ping: $!";
open (OK, "> netgroup.ok")                      or die "Can't open netgroup.ok: $!";

foreach my $machine (@machines)
{
        chomp($machine);
        print " \n----------- $machine \n";
        if ( my $ip = nslookup( domain => "$machine", type => 'A' ) )
        {
                if (  my $fqdn = nslookup ( domain => $ip, type => 'PTR' ) )
                {
                    if ( $machine ne $fqdn )
                    {
                        # original name differs from resolved IP, check is it problem or name is alias
                        if ( my $realmachine = nslookup ( domain => "$machine", type => 'CNAME' ) )
                        {
                        # OK: original name is alias, continue with ping test
                        print "ALIAS: $machine" . "\n" . "IP: $ip" . "\n" . "REALNAME: $realmachine \n";

                        my $p = Net::Ping->new();
                           if ( $p->ping($realmachine) )
                           {
                           print "PING OK: $realmachine \n";
                           # print to netgroup.ok
                           print OK "$machine (alias for $realmachine) \n";
                           }
                           else
                           {
                           print "PING PROBLEM: $realmachine \n";
                           # print to netgroup.problem.ping
                           print PINGPROBLEM "$machine (alias for $realmachine) \n";
                           }
                        $p->close();
                        }
                        else
                        {
                        # PROBLEM: original name differs from resolved IP
                        print "ORIG: $machine" . "\n" . "IP: $ip" . "\n" . "PTR_Problem: $machine differs from resolved IP ($fqdn) \n";
                        # print to netgroup.problem.dns
                        print DNSPROBLEM "$machine (differs from resolved IP: $fqdn) \n";
                        }
                    }
                    else
                    {
                    # OK: original name is same as resolved IP, continue with ping test
                    print "ORIG: $machine" . "\n" . "IP: $ip" . "\n" . "PTR_Resolv: $fqdn \n" ;

                    my $p = Net::Ping->new();
                        if ( $p->ping($machine) )
                        {
                        print "PING OK: $machine \n";
                        # print to netgroup.ok
                        print OK "$machine \n";
                        }
                        else
                        {
                        print "PING PROBLEM: $machine \n";
                        # print to netgroup.problem.ping
                        print PINGPROBLEM "$machine \n";
                        }
                    $p->close();
                    }
                }
                else
                {
                # PROBLEM: IP is resolved, but reverse lookup failes
                print "Can't find FQDN from $ip \n";
                # print to netgroup.problem.dns
                print DNSPROBLEM "$machine (Can't find FQDN from $ip) \n";
                }
        }
        else
        {
        # PROBLEM: original name can't resolve to IP
        print "Can't find IP of $machine \n";
        # print to netgroup.problem.dns
        print DNSPROBLEM "$machine (Can't find IP) \n";
        }

}

close (DNSPROBLEM) or die "Can't close netgroup.problem.dns: $!";
close (PINGPROBLEM) or die "Can't close netgroup.problem.ping: $!";
close (OK) or die "Can't close netgroup.ok: $!";

exit 0

Back to the main page