Send Netdot-users mailing list submissions to
[email protected]
To subscribe or unsubscribe via the World Wide Web, visit
https://osl.uoregon.edu/mailman/listinfo/netdot-users
or, via email, send a message with subject or body 'help' to
[email protected]
You can reach the person managing the list at
[email protected]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Netdot-users digest..."
Today's Topics:
1. NAT information on Netdot (Nico)
2. Re: Layer 2 topology discovery Fortigate 3240c vs cisco 3750
stack (Brian Candler)
----------------------------------------------------------------------
Message: 1
Date: Tue, 28 Oct 2014 23:41:48 +0100
From: Nico <[email protected]>
Subject: [Netdot-users] NAT information on Netdot
To: "[email protected]" <[email protected]>
Message-ID:
<cakxqfmshtzmtxdyvo-1zc2c9k4jmue0nxhp--rmoyd_gckz...@mail.gmail.com>
Content-Type: text/plain; charset=UTF-8
Hello,
I've been thinking for some time how to store NAT information on
Netdot, first i used simply the description of the ipblock, then i
thougt using DNS registers, and i think it's working quite nicely so
i'm sharing it.
First example, something most of us have, IP public addresses mapped
to our private address.
For this i created a Zone ipinet and for each entry of public IP >
internal IP (easy to get and parse from the firewalls i've worked
with).
With a example let's say i have the internet IP 1.1.1.1 NATted to my
internal IP 192.168.1.1
I created a bind zone file contaning:
1.1.1.1 IN A 192.168.1.1
192.168.1.1 IN A 1.1.1.1
And imported the zone file to the zone ipinet
So when i browse an internal IP wich is Natted on internet i see on
the DNS section an entry like 1.1.1.1.ipinet (and other DNS registers
it may have).
The same when i browse internet address that have an internal "map".
Next i did the same for another overlapping addresses we have on a
different zone, where sometimes we publish and access NATted IPs.
Then i thought that it will be nice to do the same for the load
balancing VIP > real IPs schemas.
We use (still) cisco CSS load balancers, and it doesn't have an easy
way to say this vip balances on those ips, so i had to wrote a script
(in python) to parse the configuration files of the CSS, then with the
information i build a new dns zone to import on netdot (i called it
iplb).
CSS have contents with associated VIP addresses and associated services.
Services have associated IPs that corresponds to real server IP.
So after the parsing i created bind files with
VIP IN A SIP (service IP)
VIP IN A SIP2
SIP IN A VIP
SIP IN A VIP2
etc.
and the other way around, so when i browse a VIP in Netdot i can see
all the real server's IP balanced on that VIP (as a lot of A records
pointing to that IP) and the other way around. For information sake i
added also the service and content name here and there as A records.
In the process of doing all this i noticed that the DNS record
function in Netdot can only search DNS A records (maybe PTR didn't
try) but not for example TXT, wich renders this type of fields
difficult to access. Becouse of this i ended using up a combination of
VIP+_content_name and SIP+_service name in my A records, this way i
can look for balanced IPs using the service or content name.
Sometime soon i'll do the same for ACE (cisco 6500 load balancers)
configuration files.
The python script i used to parte the css configuration:
It won't work out of the box without some changes or creating a
na_config.py file with some parameters (like netdot location, and css
file directory, ftp user to access the CSS and few more), so if
someone is interested say so and i'll tune it. Edit the lblist
dictionary to set it to your 'css_name':'css_ip', it will try to open
the css config file with the css_name.
netdot@ov01lnxvg9:/opt/netdot/netdot/netdot-adds> cat bin/getlbdata.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import na_config
import MySQLdb
from subprocess import call
def get_lb_configs(lblist, LOCAL_CONFIG_DIR):
import na_config
REMOTE_CONFIG_FILE = " /Archive/startup-config"
FTP_CMD="/usr/bin/ncftpget"
for name,ip in lblist.items():
print name,ip
CMD = [FTP_CMD,"-u"+na_config.radiuscgsiuser, "-p"+na_config.radiuscgsipass
,ip,REMOTE_CONFIG_FILE,LOCAL_CONFIG_DIR + name]
print CMD
def parse_css11500_file (configfile, css_file):
'''Recibe como par?metro un string conteniendo el fichero de configuraci?n
devuelve un dict con las diferentes secciones, ips, vips, balanceador, nombre
servicio, puertos por cada vip'''
import re
import pprint
service = dict()
tservice = dict()
content = dict()
tcontent = dict()
group = dict()
tgroup = dict()
sections = re.split("\r\x00\r\n\r\x00\r\n", configfile)
for section in sections:
lines = re.split("\r\x00\r\n", section)
#borrar los comentarios del fichero
#lines = [s for s in lines if s[0] != '!']
if len(lines[0]) > 0:
if lines[0][0] == '!' and len(lines) > 1:
lines = lines[1:]
if lines[0][0:7] == 'service':
tservice = parse_css11500_service (lines, css_file)
if tservice != None:
service.update(tservice)
elif lines[0][0:10] == ' content ':
tcontent = parse_css11500_content (lines, css_file)
if tcontent != None:
content.update(tcontent)
elif lines[0][0:5] == 'group':
tgroup = parse_css11500_group (lines, css_file)
if tgroup != None:
group.update(tgroup)
else:
pass
output_zone_file (service, group, content)
# pprint.pprint(service)
# pprint.pprint(content)
# pprint.pprint(group)
def output_zone_file (service, group, content):
'''Recibe como par?metro los dicts generados a partir de los ficheros de
configuraci?n y crea los ficheros de zona dns para importar a Netdot'''
#import pprint
#print " -------------- GROUP --------------------"
#pprint.pprint(group)
#print " -------------- CONTENT ------------------"
#pprint.pprint(content)
#print " -------------- SERVICE ------------------"
#pprint.pprint(service)
for content_name,data in content.items():
for content_service in content[content_name]['service']:
print ("z_c_{cip}.{cn}\tIN\tA\t{sip}\n"
"z_c_{cn}\tIN\tA\t{cip}\n"
"z_s_{sip}.{sn}\tIN\tA\t{cip}\n"
"z_s_{sn}\tIN\tA\t{sip}"
"").format(
#"{2}.{0}\tIN\tA\t{1}\n"
#"{2}.{0}\tIN\tTXT\t{1} > {2} {0} {3} {4}"
cn = content_name,
cip = data['vip'],
sip = service[content_service]['ip'],
sport = service[content_service]['port'] if 'port' in
service[content_service] else 0,
css = service[content_service]['css'],
sn = content_service)
#for service_name,data in service.items():
# print "{1}\tIN\tA\t{0}".format(
# data['ip'],
# service_name
# )
'''Parece que los grupos y los content una vez explotados contienen la misma
informaci?n. as? que lo comento'''
#for group_name,data in group.items():
# if 'service' in group[group_name]:
# for group_service in group[group_name]['service']:
# print ("{1}.{0}\tIN\tA\t{2}\n"
# "{1}.{0}\tIN\tTXT\t{1} > {2} {0} {3} {4}\n"
# "{2}.{0}\tIN\tA\t {1}\n"
# "{2}.{0}\tIN\tTXT\t{1} > {2} {0} {3} {4}").format(
# group_name,
# data['vip'],
# service[group_service]['ip'],
# service[group_service]['css'],
# 'group')
# if 'destination_service' in group[group_name]:
# for group_service in group[group_name]['destination_service']:
# print ("{1}.{0}\tIN\tA\t{2}\n"
# "{1}.{0}\tIN\tTXT\t{1} > {2} {0} {3}\n"
# "{2}.{0}\tIN\tA\t{1}\n"
# "{2}.{0}\tIN\tTXT\t{1} > {2} {0} {3} {4}").format(
# group_name,
# data['vip'],
# service[group_service]['ip'],
# service[group_service]['css'],
# 'group')
def parse_css11500_content (config, css_file):
'''Recibe una seccion content parsea los datos y los devuelve en un dict si
existe el par?metro vip address y None en otro caso'''
data = dict()
service = []
for line in config:
if line[0:10] == " content ":
content_name = line[10:].strip()
elif line[0:16] == " add service ":
service.append(line[16:].strip())
elif line[0:16] == " vip address ":
vip = line[16:].strip()
elif line[0:9] == " port ":
data['port'] = line[9:].strip()
elif line[0:20] == " redundant-index ":
data['redundant_index'] = line[20:].strip()
if 'vip' in locals():
data['vip'] = vip
data['css'] = css_file
if len(service) > 0:
data['service'] = service
d = {content_name:data}
return d
else: return None
def parse_css11500_group (config, css_file):
'''Recibe una seccion group parsea los datos y los devuelve en un
dict si existe
el par?metro vip address y None en otro caso'''
data = dict()
destination_service = []
service = []
for line in config:
if line[0:6] == "group ":
group_name = line[6:].strip()
elif line[0:26] == " add destination service ":
destination_service.append(line[26:].strip())
elif line[0:14] == " add service ":
service.append(line[14:].strip())
elif line[0:14] == " vip address ":
vip = line[14:].strip()
elif line[0:6] == " port":
data['port'] = line[6:].strip()
elif line[0:23] == " keepalive type named ":
data['keepalive_type'] = line[23:].strip()
if 'vip' in locals():
data['vip'] = vip
data['css'] = css_file
if len(destination_service) > 0:
data['destination_service'] = destination_service
if len(service) > 0:
data['service'] = service
d = {group_name:data}
return d
else: return None
def parse_css11500_service (config, css_file):
'''Recibe una seccion service parsea los datos y los devuelve en un
dict si exis
te el par?metro ip address y None en otro caso'''
import re
data = dict()
for line in config:
if line[0:7] == "service":
service_name = line[7:].strip()
elif line[3:15] == "redundant-index":
data['redundant_index'] = line[15:].strip()
elif line[0:13] == " ip address ":
ip = line[13:].strip()
elif line[0:6] == " port":
data['port'] = line[6:].strip()
elif line[0:23] == " keepalive type named ":
data['keepalive_type'] = line[23:].strip()
if 'ip' in locals():
data['ip'] = ip
data['css'] = css_file
d = {service_name:data}
return d
else: return None
# ------------ main ----------------------------------------------------------
lblist={
'css-dmz-1':'10.10.15.248',
'css-alta-1':'10.10.15.245',
'css-integ-1':'10.10.15.242',
'css-host-1':'10.10.15.226',
}
# 'css-integ-2':'10.10.15.244'
# 'css-alta-2':'10.10.15.243',
# 'css-dmz-2':'10.10.15.249',
# 'css-host-2':'10.10.15.247',
css = dict()
NETDOT_IMPORT_FILE = (na_config.netdot_prod+"/"+na_config.netdot_nameversion+
"/import/import_bind_zones.pl")
TMPFILE = na_config.netdot_adds+"/tmp/iplb.txt"
DEBUG = True
LOCAL_CONFIG_DIR = na_config.netdot_adds+"/etc/"
print """$TTL 86400
@ IN SOA netdot.ejemplo.es. quiensea.ejemplo.es. (
2014101500 ;serial
1800 ;refresh
36000 ;retry
1728000 ;expire
28800 ) ;minimum
@ 28800 IN NS netdot.ejemplo.es."""
for name, ip in lblist.items():
with open (LOCAL_CONFIG_DIR+"/"+name, "r") as myfile:
configfile=myfile.read()
css = parse_css11500_file(configfile, name)
# f = open(TMPFILE,'w')
#CMD=[NETDOT_IMPORT_FILE,TMPFILE]
#r = call(CMD)
Greeitings,
--
Nico
------------------------------
Message: 2
Date: Tue, 28 Oct 2014 23:10:37 +0000
From: Brian Candler <[email protected]>
Subject: Re: [Netdot-users] Layer 2 topology discovery Fortigate 3240c
vs cisco 3750 stack
To: Nico <[email protected]>, "[email protected]"
<[email protected]>
Message-ID: <[email protected]>
Content-Type: text/plain; charset=windows-1252; format=flowed
On 28/10/2014 13:47, Nico wrote:
> On port2 of fortinet i have the
> - mac 085B0E2D85A3.
> - And according to Netdot no vlan using that port.
This is usually SNMP::Info not being able to get the information, which
in turn is usually because the device doesn't support the standard MIBs
and SNMP::Info doesn't know how to query device-specific MIBs for that
kind of device.
Here are a couple of test scripts you can use; you can take the output
to the SNMP::Info mailing list.
-------- test_vlan.pl
use SNMP::Info;
use Data::Dumper;
my $info = new SNMP::Info (
AutoSpecify => 1,
Debug => 1,
#DebugSNMP => 3,
DestHost => $ARGV[0] || 'localhost',
Community => $ARGV[1] || 'public',
Version => 2
);
my $class = $info->class();
print " Using device sub class : $class\n";
#print Dumper($info);
print Dumper($info->qb_vlans);
#print Dumper($info->i_stp_bridge);
#print Dumper($info->i_stp_port);
#print Dumper($info->i_stp_state);
#print Dumper($info->i_vlan_membership);
--------
-------- test_lldp.pl
use SNMP::Info;
#use Data::Dumper;
my $lldp = new SNMP::Info (
AutoSpecify => 1,
Debug => 1,
DestHost => $ARGV[0] || 'localhost',
Community => $ARGV[1] || 'public',
Version => 2
);
my $class = $lldp->class();
print " Using device sub class : $class\n";
$haslldp = $lldp->hasLLDP() ? 'yes' : 'no';
# Print out a map of device ports with LLDP neighbors:
my $interfaces = $lldp->interfaces();
my $lldp_if = $lldp->lldp_if();
my $lldp_ip = $lldp->lldp_ip();
my $lldp_port = $lldp->lldp_port();
#print Dumper($interfaces,$lldp_if,$lldp_ip,$lldp_port);
foreach my $lldp_key (keys %$lldp_ip){
my $iid = $lldp_if->{$lldp_key};
my $port = $interfaces->{$iid};
my $neighbor = $lldp_ip->{$lldp_key};
my $neighbor_port = $lldp_port->{$lldp_key};
print "Port : $port connected to $neighbor / $neighbor_port\n";
}
--------
------------------------------
_______________________________________________
Netdot-users mailing list
[email protected]
https://osl.uoregon.edu/mailman/listinfo/netdot-users
End of Netdot-users Digest, Vol 71, Issue 7
*******************************************