#!/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]} ') 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