1#!/usr/bin/perl
2
3###############################################
4# Netmagis tool
5# Parse the network configurations of the host
6# and convert them to IOS pseudo CLI
7###############################################
8
9use strict;
10
11###############################################
12# IMPORTANT !
13# LOCAL settings
14#
15# set here the SNMP community used by the snmp
16# agent of this serveur
17our $snmp_community = "public";
18#
19# enable here the portmac collection
20# set 0 to disable
21# set 1 to enable
22our $portmac = 0;
23#
24# enable here the ipmac collection
25# set 0 to disable
26# set 1 to enable
27our $ipmac = 0;
28#
29# enable here the traffic statistics collectiona
30# set 0 to disable
31# set 1 to enable
32our $traffic_stats = 0;
33###############################################
34
35# Special tunning for local settings
36# To alter values of $snmp_community, $portmac, $ipmac and $traffic_stats
37# variables you must create the following file and set %sensor_type fields.
38# This is very usefull is case of script upgrade.
39if(-e "/home/conf/parsenet-options.pl")
40{
41        require "/home/conf/parsenet-options.pl";
42}
43
44
45our %net_struct;
46our %host;
47my $ifname;
48my $router;
49
50my $ifconfig = `ifconfig`;
51my $routage = `sysctl net.inet.ip.forwarding`;
52my $hostname = `hostname`;
53my $systype=`uname -s`;
54chomp($systype);
55
56# parsing du hostname
57chomp $hostname;
58
59if($hostname =~ /\./)
60{
61	my @fqdn = split(/\./,$hostname);
62	$host{name} = $fqdn[0];
63	$host{domain} = $fqdn[1];
64
65	for(my $i = 2; $i < @fqdn; $i++)
66	{
67		$host{domain} = "$host{domain}.$fqdn[$i]";
68	}
69}
70else
71{
72	$host{name} = $hostname;
73	$host{domain} = "";
74}
75
76
77# is the server a router?
78if($routage=~/net.inet.ip.forwarding.*([0-1])/)
79{
80	$router = $1;
81	$net_struct{router}{status} = $1;
82	$net_struct{router}{type} = "router";
83}
84
85# parsing de de la commande ifconfig
86my @l = split(/\n/,$ifconfig);
87
88for(my $i=0;$i<@l;$i++)
89{
90	if($l[$i]=~/^(.*): flags=[0-9a-zA-Z]+<([A-Za-z0-9]+),/)
91	{
92                $ifname = $1;
93		if ($2 eq "UP")
94		{
95			$net_struct{$ifname}{status} = $2;
96		}
97		else
98		{
99			$net_struct{$ifname}{status} = "DOWN";
100		}
101	}
102	if($l[$i]=~/^(.*): flags=[0-9a-zA-Z]+<>/)
103	{
104                $ifname = $1;
105		$net_struct{$ifname}{status} = "UNKNOWN";
106	}
107	if($l[$i]=~/vlan: ([0-9]+) .*parent interface: ([A-Za-z0-9]+)/)
108	{
109		#vlan: 977 priority: 0 parent interface: em0
110		$net_struct{$ifname}{type} = "vlan";
111		$net_struct{$ifname}{vlanid} = $1;
112		$net_struct{$ifname}{parent} = $2;
113	}
114	if($l[$i]=~/media: Ethernet/)
115	{
116		$net_struct{$ifname}{type} = "Ethernet";
117	}
118	if($l[$i]=~/groups: ([A-Za-z0-9]+)/)
119	{
120		$net_struct{$ifname}{type} = $1;
121	}
122	if($l[$i]=~/(vlan[0-9]+) flags=[0-9a-zA-Z]+/)
123	{
124		$net_struct{$ifname}{vlanif}{$1} = 1;
125	}
126	if($l[$i]=~/inet ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+) netmask ([0-9a-fA-FxX\.]+)/)
127        {
128		my $ip = $1;
129		my $nm = $2;
130		if($nm =~ s/^0x([\da-f]{8})/\1/i)
131		{
132			$nm = join '.', unpack "C*", pack "H*", $nm;
133		}
134                $net_struct{$ifname}{inet}{"$ip $nm"} = 1;
135        }
136	if($l[$i]=~/inet6 ([0-9a-fA-F:]+) prefixlen ([0-9]+)/ && $l[$i]!~/inet6 fe80:/)
137        {
138                $net_struct{$ifname}{inet6}{"$1/$2"} = 1;
139        }
140	if($l[$i]=~/lladdr ([0-9a-fA-F:]+)/)
141	{
142		$net_struct{$ifname}{mac} = $1;
143	}
144	if($l[$i]=~/ether ([0-9a-fA-F:]+)/)
145	{
146		$net_struct{$ifname}{mac} = $1;
147	}
148	if($l[$i]=~/trunkport ([0-9a-zA-Z]+)/)
149	{
150		$net_struct{$ifname}{trunk}{$1} = 1;
151		$net_struct{$1}{trunkmember} = $ifname;
152	}
153}
154
155read_tab_asso();
156
157print "!\n!\n! uname: $systype\n";
158print "!\n!\n! IOS like : \n! ----------\n!\n!\n";
159
160gen_ios_output();
161
162#############################################################
163# lecture d'un tableau associatif a 2 dimensions
164#
165sub read_tab_asso
166{
167        foreach my $key (sort keys %net_struct)
168        {
169                print "! $key {\n";
170                foreach my $kkey (sort keys %{$net_struct{$key}})
171                {
172			if($kkey eq "vlanif" || $kkey eq "inet" || $kkey eq "inet6" || $kkey eq "trunk")
173			{
174				print "! \t$kkey -> \n";
175				foreach my $kkkey (sort keys %{$net_struct{$key}{$kkey}})
176				{
177					print "! \t\t -> $kkkey\n";
178				}
179			}
180			else
181			{
182                        	print "! \t$kkey -> $net_struct{$key}{$kkey}\n";
183			}
184                }
185                print "! }\n";
186        }
187}
188
189sub gen_ios_output
190{
191	printhost();
192
193	my $bridge_group = 0;
194
195	# traitement des routers
196	foreach my $key (sort keys %net_struct)
197        {
198		if($net_struct{$key}{type} eq "router" && $net_struct{$key}{wr} != 1)
199                {
200                        if($net_struct{$key}{status} == 1)
201                        {
202                                print "ip-routing\n!\n";
203                        }
204                        else
205                        {
206                                print "no ip-routing\n!\n";
207                        }
208
209			$net_struct{$key}{wr} = 1;
210                }
211	}
212
213	# traitement des bridges
214	foreach my $key (sort keys %net_struct)
215        {
216		# si on trouve un bridge
217		if($net_struct{$key}{'type'} eq "bridge" && $net_struct{$key}{wr} != 1)
218		{
219			# equipement en mode bridge
220			print "bridge irb\n!\n";
221
222			$bridge_group ++;
223
224			# interface bridge
225			print "interface BVI$bridge_group\n";
226			# ecriture adresses IP associees au bridge
227			foreach my $ip (sort keys %{$net_struct{$key}{inet}})
228        		{
229                		print " ip address $ip\n";
230        		}
231			foreach my $ip6 (sort keys %{$net_struct{$key}{inet6}})
232                        {
233                                print " ip address $ip6\n";
234                        }
235
236			print "!\n";
237
238			foreach my $kkey (sort keys %{$net_struct{$key}{vlanif}})
239			{
240				printiface($kkey,$bridge_group);
241			}
242
243			$net_struct{$key}{wr} = 1;
244		}
245	}
246
247	# les interfaces qui suivent ne font pas partie d'un bridge-group
248	$bridge_group = 0;
249
250	# ecriture des autres interfaces
251	foreach my $key (sort keys %net_struct)
252        {
253		if(($net_struct{$key}{'type'} eq "Ethernet" || $net_struct{$key}{'type'} eq "vlan")
254			&& $net_struct{$key}{wr} != 1)
255		{
256			printiface($key,$bridge_group);
257		}
258	}
259
260	# ecriture des parametrages SNMP
261	print "snmp-server community $snmp_community RO\n";
262	print "snmp-server chassis-id $host{name}\n";
263
264	my $sysloc_string = "snmp-server location";
265	my $print_loc = 0;
266	if($portmac == 1)
267	{
268	    $sysloc_string = "$sysloc_string <P>";
269	    $print_loc = 1;
270	}
271	if($ipmac == 1)
272	{
273	    $sysloc_string = "$sysloc_string <I>";
274	    $print_loc = 1;
275	}
276	if($print_loc == 1)
277	{
278	    print "$sysloc_string\n";
279	}
280	print "!\n";
281}
282
283sub printiface
284{
285	my ($name,$bridge_group) = @_;
286
287	if($net_struct{$name}{wr} != 1)
288	{
289		# si on est en presence d'une interface vlan
290		if($net_struct{$name}{type} eq "vlan")
291		{
292			print "interface $name\n";
293
294			if($traffic_stats == 1)
295			{
296			    my $link = $net_struct{$net_struct{$name}{parent}}{mac};
297                            $link =~ s/://g;
298			    print " description <X M$host{name}$link\.$net_struct{$name}{vlanid}>\n";
299			}
300			else
301			{
302			    print " description X\n";
303			}
304			#print " description <X M$host{name}$link\.$net_struct{$name}{vlanid}>\n";
305			print " parent-iface $net_struct{$name}{parent}\n";
306			print " encapsulation dot1Q $net_struct{$name}{vlanid}\n";
307		}
308		# si on est en presence d'un trunk
309		elsif($net_struct{$name}{type} eq "Ethernet" && exists $net_struct{$name}{trunk})
310		{
311			print "interface $name\n";
312
313			if($traffic_stats == 1)
314                        {
315                            print " description <X M$host{name}.$name>\n";
316                        }
317                        else
318                        {
319                            print " description X\n";
320                        }
321		}
322        	else
323		{
324			print "interface $name\n";
325			if($net_struct{$name}{status} eq "UP" && $net_struct{$name}{mac} =~ /[0-9a-fA-F:]+/)
326		 	{
327				my $link = $net_struct{$name}{mac};
328				$link =~ s/://g;
329
330				if(exists $net_struct{$name}{trunkmember})
331                                {
332                                        $link = "$link-$name";
333                                }
334
335				if($traffic_stats == 1)
336				{
337				    print " description <L$link M$host{name}$link>\n";
338				}
339				else
340				{
341				    print " description L$link\n";
342				}
343			}
344			else
345			{
346				print " description X\n";
347			}
348
349			if(exists $net_struct{$name}{trunkmember})
350			{
351				print " channel-group $net_struct{$name}{trunkmember} mode auto\n"
352			}
353
354		}
355		# ajout dans le bridge group de l'interface
356		if($bridge_group > 0)
357		{
358			print " bridge-group $bridge_group\n"
359		}
360
361		# ecriture adresses IP
362		foreach my $ip (sort keys %{$net_struct{$name}{inet}})
363		{
364			print " ip address $ip\n";
365		}
366		foreach my $ip6 (sort keys %{$net_struct{$name}{inet6}})
367       		{
368                 	print " ip address $ip6\n";
369        	}
370
371		print "!\n";
372
373		$net_struct{$name}{wr} = 1;
374	}
375}
376
377sub printhost
378{
379	if($host{name} ne "")
380	{
381		print "hostname $host{name}\n!\n";
382	}
383	if($host{domain} ne "")
384	{
385		print "ip domain name $host{domain}\n!\n";
386	}
387}
388