200 lines
7.5 KiB
Python
200 lines
7.5 KiB
Python
#!/usr/bin/python
|
||
import bs4
|
||
from lxml import etree
|
||
import sys
|
||
import random
|
||
|
||
def extractstring (tree, xpathstr):
|
||
"""Dirty helper"""
|
||
name = tree.xpath(xpathstr)
|
||
return name[0].text if len(name) > 0 else ''
|
||
types = {
|
||
'Ordinateur': 'Ordinateur',
|
||
'Portable': 'Ordinateur',
|
||
'Rechner': 'Ordinateur',
|
||
'Notebook': 'Ordinateur',
|
||
'Routeur': 'Routeur',
|
||
'Vermittlungsrechner': 'Routeur',
|
||
'Switch': 'Switch',
|
||
}
|
||
class Knot:
|
||
def __init__ (self, ident, typ, name, ips, gw, dns, rip=None, dnsrecords={}):
|
||
"""Dirty knot. netmask is fixed to /24"""
|
||
self.id = ident
|
||
self.typ = types[typ]
|
||
self.name = name
|
||
self.ips = ips
|
||
self.gw = gw
|
||
self.dns = dns
|
||
self.rip = rip
|
||
self.dnsrecords = dnsrecords
|
||
def __str__ (self):
|
||
return f"{self.typ}:{self.name}:{self.ips}"
|
||
|
||
def has_gw (self):
|
||
return self.gw != ''
|
||
|
||
class Network:
|
||
def __init__ (self, filename):
|
||
self.filename = filename
|
||
self.knots = {}
|
||
self.wires = []
|
||
with open(filename, 'r') as f:
|
||
soup = bs4.BeautifulSoup(f , 'lxml')
|
||
for element in soup.findAll(class_="filius.gui.netzwerksicht.GUIKnotenItem"):
|
||
tree = etree.XML(str(element))
|
||
ident = element.attrs['id'] if 'id' in element.attrs else random.randint(0,10000)
|
||
self.knots[ident] = Knot(
|
||
ident,
|
||
extractstring(tree, '//*[@property="typ"]/string'),
|
||
extractstring(tree, '//*[@property="name"]/string'),
|
||
[ip.text for ip in tree.xpath('//*[@property="ip"]/string')],
|
||
extractstring(tree, '//*[@property="gateway"]/string'),
|
||
extractstring(tree, '//*[@property="dns"]/string'),
|
||
extractstring(tree, '//*[@property="ripEnabled"]/boolean') == 'true',
|
||
{ s.split(' ')[0].upper():s.split(' ')[-1] for s in (extractstring(tree, '//*[@property="dateiInhalt"]/string') or '').split('\n') if s != ''},
|
||
)
|
||
for element in soup.findAll(property="kabelpanel"):
|
||
tree = etree.XML(str(element))
|
||
self.wires.append((
|
||
tree.xpath('//*[@property="ziel1"]/object')[0].attrib['idref'],
|
||
tree.xpath('//*[@property="ziel2"]/object')[0].attrib['idref'],
|
||
))
|
||
|
||
def same_network (self, ip1, ip2):
|
||
return ip1.split('.')[0:2] == ip2.split('.')[0:2]
|
||
|
||
def ips_of (self, ident):
|
||
return self.knots[ident].ips if ident in self.knots else []
|
||
|
||
def gw_of (self, ident):
|
||
return self.knots[ident].gw if ident in self.knots else None
|
||
|
||
def dns_of (self, ident):
|
||
return self.knots[ident].dns if ident in self.knots else None
|
||
|
||
def ident_of (self, name):
|
||
for k in self.knots:
|
||
if self.knots[k].name.upper() == name.upper():
|
||
return k
|
||
return None
|
||
|
||
def gateway_of (self, ident):
|
||
"""Returns gws id of ident"""
|
||
for k in self.knots:
|
||
if self.knots[ident].gw in self.knots[k].ips:
|
||
return k
|
||
|
||
def ip_duplicates (self):
|
||
ips = []
|
||
for k in self.knots:
|
||
for ip in self.knots[k].ips:
|
||
if ip in ips:
|
||
return True
|
||
else:
|
||
ips.append(ip)
|
||
return False
|
||
|
||
def connected_to (self, ident):
|
||
"""Returns a list of knot connected to ident"""
|
||
return [ w[(i+1)%2] for w in self.wires for i in range(2) if w[i] == ident]
|
||
|
||
|
||
def local_path_exists (self, ident, ip):
|
||
"""Test if a local network path exists between ident and ip. Assuming there is no loops on a local network :D"""
|
||
visited = []
|
||
tovisit = [ident]
|
||
|
||
while len(tovisit) > 0:
|
||
knot = tovisit.pop()
|
||
visited.append(knot)
|
||
for k in self.connected_to(knot):
|
||
if ip in self.knots[k].ips:
|
||
return True
|
||
elif k not in visited:
|
||
tovisit.append(k)
|
||
return False
|
||
|
||
def get_routers (self):
|
||
return [ k for k in self.knots if self.knots[k].typ == 'Routeur' ]
|
||
|
||
def ping (self, knot, dest):
|
||
k = self.knots[knot]
|
||
# Is the destination on our local network?
|
||
for ip in k.ips:
|
||
if self.same_network(ip, dest):
|
||
return self.local_path_exists(knot, dest)
|
||
# Have we got a reachable gw?
|
||
if k.has_gw() and self.local_path_exists(knot, k.gw):
|
||
return self.local_path_exists(self.gateway_of(knot), dest)
|
||
return False
|
||
|
||
|
||
def correction (filename):
|
||
"""Returns dict criterion:mark, mark, total"""
|
||
res = {}
|
||
n = Network(filename)
|
||
for num, lettre in enumerate(['D', 'E', 'F']):
|
||
num +=1
|
||
ident = n.ident_of(lettre)
|
||
ips = n.knots[ident].ips if ident is not None else []
|
||
res[f'- L’ordinateur {lettre} peut pinger l’adresse IP 10.1.200.{num}'] = int(n.ping(ident, f'10.1.200.{num}')) if ident is not None else 0
|
||
res[f'- L’ordinateur {lettre} a une IP valide'] = int(len(ips) == 1 and ips[0].startswith('10.2.200.'))
|
||
|
||
res['- Il n’y a pas d’adresses IP en double'] = int(not n.ip_duplicates())
|
||
|
||
ident = n.ident_of('serveur')
|
||
ips = n.knots[ident].ips if ident is not None else []
|
||
res[f'- Le serveur a une adresse IP valide'] = int(len(ips) == 1 and not ips[0].startswith('10.1.200.') and not ips[0].startswith('10.2.200.'))
|
||
|
||
routers = n.get_routers()
|
||
ips_routers = n.knots[routers[0]].ips if len(routers) == 1 else []
|
||
if ips_routers == []:
|
||
print(routers, file=sys.stderr)
|
||
for k in n.knots:
|
||
print(n.knots[k], file=sys.stderr)
|
||
res[f'- Le routeur a l’adresse IP 10.1.200.254'] = int('10.1.200.254' in ips_routers)
|
||
res[f'- Le routeur a l’adresse IP 10.2.200.254'] = int('10.2.200.254' in ips_routers)
|
||
ip_router = ''
|
||
for ip in ips_routers:
|
||
if not ip.startswith('10.2.200.') and not ip.startswith('10.1.200.'):
|
||
ip_router = ip
|
||
break
|
||
res['- Le routeur a une adresse IP vers le serveur'] = int(ip_router != '')
|
||
res['- Le routage est activé'] = int(n.knots[routers[0]].rip) if len(routers) == 1 else 0
|
||
|
||
res['- Le routeur et le serveur ont des adresses IP avec la même partie réseau'] = int(ip_router.startswith('.'.join(ips[0].split('.')[0:2]))) if len(ips) == 1 else 0
|
||
|
||
for num, lettre in enumerate(['A', 'B', 'C']):
|
||
num +=1
|
||
ident = n.ident_of(lettre)
|
||
res[f'- L’ordinateur {lettre} a l’adresse IP 10.1.200.{num}'] = int(f'10.1.200.{num}' in n.ips_of(ident))
|
||
res[f'- L’ordinateur {lettre} a la passerelle 10.1.200.254'] = int('10.1.200.254' == n.gw_of(ident))
|
||
res[f'- L’ordinateur {lettre} a le serveur DNS configuré'] = int(ips[0] == n.dns_of(ident)) if len(ips) == 1 else 0
|
||
|
||
|
||
found = False
|
||
for k in n.knots:
|
||
if n.knots[k].dnsrecords != '' and 'A.' in n.knots[k].dnsrecords and n.knots[k].dnsrecords['A.'] == '10.1.200.1':
|
||
found = True
|
||
break
|
||
res[f'- Le nom DNS A se traduit par l’adresse IP 10.1.200.1'] = int(found)
|
||
|
||
|
||
|
||
|
||
return res, sum(res.values()), len(res) # Assuming all questions are worth 1 points
|
||
|
||
if __name__ == '__main__':
|
||
if len(sys.argv) != 2:
|
||
print(f'Usage:\n {sys.argv[0]} <konfiguration.xml>')
|
||
exit(1)
|
||
res, note, total = correction(sys.argv[1])
|
||
for line in res:
|
||
print(line, ' — ', res[line])
|
||
print()
|
||
print(f'Total : {note}/{total}')
|
||
|
||
# TODO critères suivants
|
||
# quelques traductions DNS
|