1 | #!/usr/bin/perl -w
|
---|
2 | #
|
---|
3 | # Syntax: mr-net-find <IP Addr>
|
---|
4 | # finds on which network device the the server is
|
---|
5 | # $Id$
|
---|
6 | #
|
---|
7 | # Copyright B. Cornec 2007-2012
|
---|
8 | # Provided under the GPL v2
|
---|
9 |
|
---|
10 | # Syntax: see at end
|
---|
11 |
|
---|
12 | use strict 'vars';
|
---|
13 | use Socket;
|
---|
14 | use Data::Dumper;
|
---|
15 | use Getopt::Long qw(:config auto_abbrev no_ignore_case);
|
---|
16 | use English;
|
---|
17 | #use lib qw (lib);
|
---|
18 | use ProjectBuilder::Version;
|
---|
19 | use ProjectBuilder::Base;
|
---|
20 |
|
---|
21 | =pod
|
---|
22 |
|
---|
23 | =head1 NAME
|
---|
24 |
|
---|
25 | mr-net-find, finds on which network device a machine is reachable
|
---|
26 |
|
---|
27 | =head1 DESCRIPTION
|
---|
28 |
|
---|
29 | mr-net-find, finds on which network device an machine is reachable
|
---|
30 | It takes the IP or named looked at as single parameter and diagnose on which device it's reachable or gives NONET if it's not.
|
---|
31 |
|
---|
32 | =head1 SYNOPSIS
|
---|
33 |
|
---|
34 | mr-net-find [-v] NFS_SERVER_NAME
|
---|
35 |
|
---|
36 | =head1 OPTIONS
|
---|
37 |
|
---|
38 | =over 4
|
---|
39 |
|
---|
40 | =item B<-v|--verbose>
|
---|
41 |
|
---|
42 | Be more verbose
|
---|
43 |
|
---|
44 | =back
|
---|
45 |
|
---|
46 | =head1 WEB SITES
|
---|
47 |
|
---|
48 | The main Web site of the project is available at L<http://www.mondorescue.org/>. Bug reports should be filled using the trac instance of the project at L<http://trac.mondorescue.org/>.
|
---|
49 |
|
---|
50 | =head1 USER MAILING LIST
|
---|
51 |
|
---|
52 |
|
---|
53 | =head1 AUTHORS
|
---|
54 |
|
---|
55 | The MondoRescue team L<http://www.mondorescue.org/> lead by Bruno Cornec L<mailto:bruno@mondorescue.org>.
|
---|
56 |
|
---|
57 | =head1 COPYRIGHT
|
---|
58 |
|
---|
59 | MondoRescue.org is distributed under the GPL v2.0 license
|
---|
60 | described in the file C<COPYING> included with the distribution.
|
---|
61 |
|
---|
62 | =cut
|
---|
63 |
|
---|
64 | # Global variables
|
---|
65 | my ($mrver,$mrrev) = pb_version_init();
|
---|
66 | my $appname = "mr-net-find";
|
---|
67 | my %opts; # CLI Options
|
---|
68 |
|
---|
69 | # Initialize the syntax string
|
---|
70 |
|
---|
71 | pb_syntax_init("$appname Version $mrver-$mrrev\n");
|
---|
72 |
|
---|
73 | GetOptions("help|?|h" => \$opts{'h'},
|
---|
74 | "man" => \$opts{'man'},
|
---|
75 | "verbose|v+" => \$opts{'v'},
|
---|
76 | ) || pb_syntax(-1,0);
|
---|
77 |
|
---|
78 | if (defined $opts{'h'}) {
|
---|
79 | pb_syntax(0,1);
|
---|
80 | }
|
---|
81 | if (defined $opts{'man'}) {
|
---|
82 | pb_syntax(0,2);
|
---|
83 | }
|
---|
84 | if (defined $opts{'v'}) {
|
---|
85 | $pbdebug = $opts{'v'};
|
---|
86 | }
|
---|
87 | pb_log_init($pbdebug, $pbLOG);
|
---|
88 |
|
---|
89 |
|
---|
90 | # Check to which network an IP balongs
|
---|
91 | sub mr_net_for_ip {
|
---|
92 |
|
---|
93 | my ($ip, $if) = @_;
|
---|
94 | my $dev = undef;
|
---|
95 |
|
---|
96 | # For each device on the system
|
---|
97 | foreach my $d (keys %$if) {
|
---|
98 | # Skip non fully activated interfaces
|
---|
99 | next if ((not defined $if->{$d}->{'nm'}) || (not defined $if->{$d}->{'net'}) || (not defined $if->{$d}->{'bcast'}));
|
---|
100 | # Get the net & bcast assuming the ip is on that net with that nm
|
---|
101 | my ($net,$bcast) = mr_net_nbcast_from_in ($ip,$if->{$d}->{'nm'});
|
---|
102 | # Is it true ?
|
---|
103 | if (($net eq $if->{$d}->{'net'}) && ($bcast eq $if->{$d}->{'bcast'})) {
|
---|
104 | # found it, return that value
|
---|
105 | $dev = $d;
|
---|
106 | last;
|
---|
107 | }
|
---|
108 | }
|
---|
109 | return($dev);
|
---|
110 | }
|
---|
111 |
|
---|
112 | sub mr_net_find_all {
|
---|
113 |
|
---|
114 | my %if;
|
---|
115 | my $if = \%if;
|
---|
116 |
|
---|
117 | my $curdev = "";
|
---|
118 | open(IP,"ip addr |") || die "Unable to read IP config\n";
|
---|
119 | while(<IP>) {
|
---|
120 | # Remove duplicate spaces
|
---|
121 | $_ =~ s/\s+/ /g;
|
---|
122 | pb_log(2,"Line: $_\n");
|
---|
123 | # Check for a new interface
|
---|
124 | my $tmp;
|
---|
125 | if (/^[0-9]+:/) {
|
---|
126 | my $dev;
|
---|
127 | my $rank;
|
---|
128 | ($rank,$dev,$tmp) = split(/:/);
|
---|
129 | pb_log(3,"$rank,$dev,$tmp");
|
---|
130 | $dev =~ s/\s*//;
|
---|
131 | $if->{$dev}->{'if'} = $dev;
|
---|
132 | $curdev = $dev;
|
---|
133 | }
|
---|
134 | ($tmp,$tmp,$if->{$curdev}->{'mac'},$tmp) = split(/ /) if (/^ link/);
|
---|
135 | ($tmp,$tmp,$if->{$curdev}->{'cidr'},$tmp) = split(/ /) if (/^ inet/);
|
---|
136 | }
|
---|
137 | close(IP);
|
---|
138 |
|
---|
139 | # Ideas Taken from http://nixcraft.com/shell-scripting/11398-simple-ipcalc-perl-script.html
|
---|
140 | foreach my $dev (keys %if) {
|
---|
141 | next if (not defined $if->{$dev}->{'cidr'});
|
---|
142 | ($if->{$dev}->{'ip'},my $cidr) = split(/\//,$if->{$dev}->{'cidr'});
|
---|
143 |
|
---|
144 | $if->{$dev}->{'nm'} = mr_net_cvt_bits_mask($cidr);
|
---|
145 |
|
---|
146 | ($if->{$dev}->{'net'},$if->{$dev}->{'bcast'}) = mr_net_nbcast_from_in($if->{$dev}->{'ip'},$if->{$dev}->{'nm'});
|
---|
147 | }
|
---|
148 | pb_log(2,"exit IP: ".Dumper($if)."\n");
|
---|
149 |
|
---|
150 | return($if);
|
---|
151 | }
|
---|
152 |
|
---|
153 |
|
---|
154 | # Improved from http://icmp.ru/man/cisco/cookbook/ciscockbk-CHP-5-SECT-3.htm
|
---|
155 | sub mr_net_cvt_bits_mask {
|
---|
156 |
|
---|
157 | my ($bits) = @_;
|
---|
158 | my $a = 0;
|
---|
159 | my $b = 0;
|
---|
160 | my $c = 0;
|
---|
161 | my $d = 0;
|
---|
162 |
|
---|
163 | if ($bits <= 8 ) {
|
---|
164 | $a = bits_to_dec($bits);
|
---|
165 | } else {
|
---|
166 | $a = 255;
|
---|
167 | if ($bits <= 16 ) {
|
---|
168 | $b = bits_to_dec($bits-8);
|
---|
169 | } else {
|
---|
170 | $b=255;
|
---|
171 | if ($bits <= 24 ) {
|
---|
172 | $c = bits_to_dec($bits-16);
|
---|
173 | } else {
|
---|
174 | $c=255;
|
---|
175 | if ($bits <= 32 ) {
|
---|
176 | $d = bits_to_dec($bits-24);
|
---|
177 | } else {
|
---|
178 | die "invalid bit count\n";
|
---|
179 | }
|
---|
180 | }
|
---|
181 | }
|
---|
182 | }
|
---|
183 | return ($a.".".$b.".".$c.".".$d);
|
---|
184 | }
|
---|
185 |
|
---|
186 | sub bits_to_dec {
|
---|
187 | my ($bits) = @_;
|
---|
188 |
|
---|
189 | if ($bits == 0 ) { return 0; }
|
---|
190 | if ($bits == 1 ) { return 128; }
|
---|
191 | if ($bits == 2 ) { return 192; }
|
---|
192 | if ($bits == 3 ) { return 224; }
|
---|
193 | if ($bits == 4 ) { return 240; }
|
---|
194 | if ($bits == 5 ) { return 248; }
|
---|
195 | if ($bits == 6 ) { return 252; }
|
---|
196 | if ($bits == 7 ) { return 254; }
|
---|
197 | if ($bits == 8 ) { return 255; }
|
---|
198 | }
|
---|
199 |
|
---|
200 | # Get Net and Broadcast from IP and Netmask
|
---|
201 | sub mr_net_nbcast_from_in {
|
---|
202 |
|
---|
203 | my ($ip,$nm) = @_;
|
---|
204 | my ($ipaddress) = unpack("N",pack( "C4",split(/\./,$ip)));
|
---|
205 | my ($netmask) = unpack( "N", pack( "C4",split(/\./,$nm)));
|
---|
206 |
|
---|
207 | # Calculate network address by logical AND operation of addr & netmask
|
---|
208 | # and convert network address to IP address format
|
---|
209 | my $net = join(".",unpack("C4",pack("N",($ipaddress & $netmask))));
|
---|
210 |
|
---|
211 | # Calculate broadcase address by inverting the netmask
|
---|
212 | # and do a logical or with network address
|
---|
213 | my $bcast = join(".",unpack("C4",pack("N",($ipaddress & $netmask)+(~ $netmask))));
|
---|
214 | return($net,$bcast);
|
---|
215 | }
|
---|
216 |
|
---|
217 | #Main
|
---|
218 |
|
---|
219 | my $nfsip = inet_ntoa(scalar gethostbyname($ARGV[0] || 'localhost'));
|
---|
220 |
|
---|
221 | my $if = mr_net_find_all();
|
---|
222 | pb_log(1,"IP: ".Dumper($if)."\n");
|
---|
223 | my $dev = mr_net_for_ip($nfsip,$if);
|
---|
224 | my $strnet = "NONET";
|
---|
225 | $strnet = $dev if (defined $dev);
|
---|
226 | pb_log(1,"NFS IP ($nfsip) is on net $strnet)\n");
|
---|
227 | pb_log(0,"$strnet\n");
|
---|